Good practice to add protected methods for sake of unit testing? - java

Say I have the following class:
public class ProblematicObject {
public static void methodToTest() {
SomeDependency dep = DependencyGetter.getDependency(SomeDependency.class);
dep.doStuff();
}
}
Is it an acceptable practice to modify and add methods to this class for the sake of making unit testing cleaner (aka avoiding PowerMock)? Here's what the class above would look like:
public class ProblematicObject {
// new
private static SomeDependency dep;
// updated
public static void methodToTest() {
getSomeDependency().doStuff();
}
// new
private SomeDependency getSomeDependency() {
if (this.dep == null) {
return DependencyGetter.getDependency(SomeDependency.class);
}
return dep;
}
// new, only used for testing, not in any impl code
#Deprecated
protected void setDependencyGetter(SomeDependency dep) {
this.dep = dep;
}
}
I seem to recall reading somewhere that adding methods for the sake of testing (instead of refactoring the problematic class) is looked down upon.

In this particular example, you are in fact improving your class design by making it testable.
This new unit test made you think from the point of view of the client of ProblematicObject and made you provide a way to inject that dependency.

Related

Refactoring static mocks in Mockito 3.4

I have a Jupiter based UnitTest in a java project where I need to mock some static methods of an external utility. Mockito 3.4 allows for mocking static methods, so no need for PowerMock any more. We all use static mocks by defining them in a try(){} block and overwriting methods on those static mocks inside the block. All fine, but things sometimes get annoying when you have to implement a non trivial mocking cascade. Which is especially annoying of you have to do that in several test cases inside your test class.
class ClassA {
public static void methodA() { ... }
public static void methodB() { ... }
}
class ClassB {
public static void methodA() { ... }
public static void methodB() { ... }
}
class ClassC {
public static void methodA() { ... }
public static void methodB() { ... }
}
class ClassX {
public int doSomething() {
// does something using static methods from classes ClassA, ClassB, ClassC
return 3;
}
}
A test class might (roughly) look like that (please excuse typos and nonsense, this is only meant as a demonstration, this is not working code):
#Test
void test_doSomething() {
int result = 0;
ClassX classX = new ClassX();
try (MockedStatic<ClassA> classAMockStatic = Mockito.mockStatic(ClassA.class);
MockedStatic<ClassB> classBMockStatic = Mockito.mockStatic(ClassB.class);
MockedStatic<ClassC> classCMockStatic = Mockito.mockStatic(ClassC.class)) {
// this is a block where static methods get overwritten, also some mocks are created
// this code does not make sense, it is just to demonstrate the issue of non trivial mocking scenarios
// situations like this often arise when mocking building patterns for example
classAMockStatic.when(ClassA::methodA).thenReturn("fooA");
ClassB classBMock = mock(ClassB.class);
when(classBMock.methodA()).thenReturn("barA");
classAMockStatic.when(ClassA::methodB).thenReturn(classBMock);
ClassC classCMock = mock(ClassC.class);
when(classCMock.someMethodA()).thenReturn("abc");
when(classCMock.methodA()).thenReturn("barA");
classAMockStatic.when(ClassA::methodA).thenReturn(classCMock);
// and so on and so on, you get the idea
result = classX.doSomething();
}
assertThat(result).equals(3);
}
Typically the question arises if this cannot be refactored to implement the mocking cascade only once. And use it in several test cases. I tried that, I was surprised to find that some of my overwritten methods worked as expected, but not all. I failed to find a working solution:
// THIS DOES NOT WORK
#Test
void test_doSomething() {
int result = 0;
ClassX classX = new ClassX();
try (MockedStatic<ClassA> classAMockStatic = createStaticMockA();
MockedStatic<ClassB> classBMockStatic = createStaticMockB();
MockedStatic<ClassC> classCMockStatic = createStaticMockC()) {
result = classX.doSomething();
}
assertThat(result).equals(3);
}
private MockedStatic<ClassA> createStaticMockA() {
MockedStatic<ClassA> classAMockStatic = Mockito.mockStatic(ClassA.class);
classAMockStatic.when(ClassA::methodA).thenReturn("fooA");
ClassB classBMock = mock(ClassB.class);
when(classBMock.methodA()).thenReturn("barA");
classAMockStatic.when(ClassA::methodB).thenReturn(classBMock);
return classAMockStatic;
}
private MockedStatic<ClassB> createStaticMockB() {
MockedStatic<ClassB> classAMockStatic = Mockito.mockStatic(ClassB.class);
ClassB classBMock = mock(ClassB.class);
when(classBMock.someMethodA()).thenReturn("aaa");
when(classBMock.someMethodB()).thenReturn("bbb");
when(classBMock.methodA()).thenReturn("barA");
classBMockStatic.when(ClassB::methodA).thenReturn(classBMock);
return classBMockStatic;
}
private MockedStatic<ClassC> createStaticMockC() {
MockedStatic<ClassC> classAMockStatic = Mockito.mockStatic(ClassC.class);
ClassC classCMock = mock(ClassC.class);
when(classCMock.someMethodA()).thenReturn("abc");
when(classCMock.methodB()).thenReturn("barC");
classCMockStatic.when(ClassC::methodA).thenReturn(classCMock);
return classCMockStatic;
}
So this looks cleared up, but does not work.
I know that I obviously could just extract the mocking section into a method and call that first in the try block. But that separates the static setup from the mock generation. And it is not as clean as my idea.
Yes, I tried implementing an execution method which accepts a lambda holding the code actually meant to be executed. So that the try(){} block gets stowed away into a method, leaving only the call to that method with a lambda in the test case. Works, but is hard to read and to understand. Not a good solution in my experience.
And yes, I also know that one should try to refactor production code so that it is easier to mock it. Sometimes that is simply not possible (read: external dependencies).
So what are my questions here?
does anyone have an idea how to achieve a clean, refactored look which actually works?
can anyone explain to me why some of the overwritten methods work as expected while others don't? I know, all the examples on the internet demonstrate that you use the straight approach, but the examples are obviously showing trivial situations.
is it really true that no one else is annoyed by that situation of have to setup the mock cascade exactly where it confuses? And that you have to reimplement it for each test case?
As Tim Moore suggests, if you have:
class StaticUtil {
public static void foo() { ... }
}
You can introduce an interface and an implementation to inject into your clients:
interface Util {
void foo();
}
class DefaultUtil {
public void foo() {
StaticUtil.foo();
}
This makes writing tests simpler as you can just mock Util in the normal way.

Code refactoring, how to disintegrate two two static functions without making parent functions non static

Context :
We are refectoring the code in order to move to micro services. We've
multiple products(A, B, C and some common code for A,B,C in monolithic
service). now we creating new sandbox for common code.
Problem :
User.java
Class User {
public **static** void init(){
List<Items> users=Items.getItemsList();
}
}
Items.java
Class Items {
public **static** Items getItemsList(){
//many static functions and dependancy
return items;
}
}
So here, both the functions are static and i want to move only User.java
to new sandbox not Items.java. how can i disintegrate this dependancy.
and i can not make User.init() non-static
Assuming sandbox means an independent project that produces a jar, then 'Items` must also exist in the sandbox, otherwise it won't compile.
But you could extract an interface from Items to something such as IItems (forgive the terrible name).
public interface IItems {
// methods...
}
which is included in the sandbox.
And create an interface for a factory such as:
public interface IItemsFactory {
List<IItem> create();
}
which is also included in the sandbox.
The ugly part is keeping User.init() as static. Using a hacky IoC pattern, set an implementation of an IItemsFactory into User. The factory will also have to be static. So User becomes something like:
public class User {
private static volatile IItemsFactory factory;
public static setFactory(IItemsFactory factory) {
User.factory = factory;
}
public static void init() {
List<IItems> users = factory.getItemsList();
}
}
The A, B, and C projects are responsible for providing an implementation of IItemFactory and setting it before calling User.init().
This is half baked and those static methods need to go away during the next refactoring iteration. Still use the IoC pattern, but inject the factory as part of the User constructor.
public class User {
private IItemsFactory factory;
public User(IItemsFactory factory) {
this.factory = factory;
}
public void init() {
List<IItems> users = factory.getItemsList();
}
}

Mock inherited method in Mockito Java

My class structure is as follows:
public class MyParentClass {
void doSomethingParent() {
System.out.println("something in parent");
}
}
public class MyClass extends MyParentClass {
protected String createDummyRequest(Holder myHolder) {
//...
super.doSomethingParent();//I want to avoid this
//...
callingDB();
return "processedOutput";
}
private void callingDB() {
System.out.println("Calling to DB");
}
}
Then my unit test:
public class UnitTest {
public void testCreateDummyRequest() {
//create my mock holder
Holder mockHolder = new Holder();
MyClass mockObj = Mockito.mock(MyClass.class);
//mock doSomethingParent()
//mock callingDB()
//as mockObj is a fully mock, but I need to run my real method
//Mockito.when(mockObj.createDummyRequest(mockHolder)).thenCallRealMethod();
mockObj.createDummyRequest(mockHolder);
//Problem: doSomethingParent() is getting called though I have mocked it
}
}
How do I prevent the calling of the super.doSomethingParent() in my method? (method which I am writing my test)
With this class structure mocking and testing is real hard. If possible, I'd advice to change the structure as in mist cases a class structure that's hard to mock and test is equally hard to extend and maintain.
So if you could change your class structure to something similar to:
public class MyClass {
private DoSomethingProvider doSomethingProvider;
private DbConnector dbConnector;
public MyClass (DoSomethingProvider p, DbConnector c) {
doSomethingProvicer = p;
dbConnector = c;
}
protected String createDummyRequest(Holder myHolder){
//...
doSomethingProvider.doSomethingParent();
//...
dbConnector.callingDB();
return "processedOutput";
}
}
Then you could easily create your instance with mocks of DoSomethingProvider and DbConnector and voila....
If you can't change your class structure you need to use Mockito.spy instead of Mockito.mock to stub specific method calls but use the real object.
public void testCreateDummyRequest(){
//create my mock holder
Holder mockHolder = new Holder();
MyClass mockObj = Mockito.spy(new MyClass());
Mockito.doNothing().when(mockObj).doSomething();
mockObj.createDummyRequest(mockHolder);
}
Note: Using the super keyword prevents Mockito from stubbing that method call. I don't know if there is a way to stub calls to super. If possible (as in you didn't override the parent method in your class), just ommit the keyword.
I faced similar issue, so I find out that using spy() can hepld.
public class UnitTest {
private MyClass myObj;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
myObj= spy(new MyClass());
}
#Test
public void mockedSuperClassMethod(){
doNothing().when((MyParentClass )myObj).doSomethingParent();
//...
}
}
This approach works for me.
I found another approach, which turned out to be very useful in my case.
In the case I had, I needed to create a new class extending another, which included a very complex (legacy code) protected final method. Due to the complexity, it wasn't really possible to refactor to use composition, so here's what I came up with.
Let's say I have the following:
abstract class Parent {
public abstract void implementMe();
protected final void doComplexStuff( /* a long parameter list */) {
// very complex legacy logic
}
}
class MyNewClass extends Parent {
#Override
public void implementMe() {
// custom stuff
doComplexStuff(/* a long parameter list */); // calling the parent
// some more custom stuff
}
}
Here's how I rearranged this code:
abstract class Parent {
public abstract void implementMe();
protected final void doComplexStuff( /* a long parameter list */) {
// very complex legacy logic
}
}
interface ComplexStuffExecutor {
void executeComplexStuff(/* a long parameter list, matching the one from doComplexStuff */);
}
class MyNewClass extends Parent {
private final ComplexStuffExecutor complexStuffExecutor;
MyNewClass() {
this.complexStuffExecutor = this::doComplexStuff;
}
MyNewClass(ComplexStuffExecutor complexStuffExecutor) {
this.complexStuffExecutor = complexStuffExecutor;
}
#Override
public void implementMe() {
// custom stuff
complexStuffExecutor.doComplexStuff(/* a long parameter list */); // either calling the parent or the injected ComplexStuffExecutor
// some more custom stuff
}
}
When creating instance of MyNewClass for "production" purposes, I can use the default constructor.
When writing unit tests, however, I'd use the constructor, where I can inject ComplexStuffExecutor, provide a mock there and only test my custom logic from MyNewClass, i.e.:
class MyNewClassTest {
#Test
void testImplementMe() {
ComplexStuffExecutor complexStuffExecutor = Mockito.mock(ComplexStuffExecutor.class);
doNothing().when(complexStuffExecutor).executeComplexStuff(/* expected parameters */);
MyNewClass systemUnderTest = new MyNewClass(complexStuffExecutor);
// perform tests
}
}
At first glance, it seems like adding some boilerplate code just to make the code testable. However, I can also see it as an indicator of how the code should actually look like. Perhaps one day someone (who would find courage and budget ;) ) could refactor the code e.g. to implement the ComplexStuffExecutor with the logic from doComplexStuff from Parent, inject it into MyNewClass and get rid of inheritance.
Here is how it can be done
public class BaseController {
public void method() {
validate(); // I don't want to run this!
}
}
public class JDrivenController extends BaseController {
public void method(){
super.method()
load(); // I only want to test this!
}
}
#Test
public void testSave() {
JDrivenController spy = Mockito.spy(new JDrivenController());
// Prevent/stub logic in super.method()
Mockito.doNothing().when((BaseController)spy).validate();
// When
spy.method();
// Then
verify(spy).load();
}
Source: https://blog.jdriven.com/2013/05/mock-superclass-method-with-mockito/

Static methods are sort of code smell?

I am recently working on TDD with JUnit and Mockito. For some purpose within a method, I am using an Util class (an utility class having methods in project context). The thing is what I am facing is how to mock such classes in Mockito. I am not able to find as such implementation regarding static methods in Mockito. Some suggest using PowerMock on top of Mockito but wouldn't that replace my JunitMockitoRunner?
The way I am using the static function is:
public void doSomething(int x){
//Some code
Y y = Util.someStaticMethod(x);
//Some more code
}
EDIT : Also I read somewhere that using static methods is a code smell and is a sign of bad design. So how should I be refactoring the design and what advantages will I be having as a result?
How should I be refactoring the design and what advantages will I be having as a result?
Well, if you need to mock the static utility method, then make it an instance method of an injectable object, so that you can inject a mock implementation of this object. The advantage is that it makes your code more testable:
public class Util {
public Y someInstanceMethod(X x) {
...
}
}
public class ClassToBeTested {
private Util util;
public ClassToBeTested(Util util) {
this.util = util;
}
public void doSomething(int x){
//Some code
Y y = util.someInstanceMethod(x);
//Some more code
}
}
public class ClassToBeTestedTest {
public void testDoSomething() {
Util mockUtil = mock(Util.class);
ClassToBeTested t = new ClassToBeTested(mockUtil);
when(mockUtil.someInstanceMethd(3)).thenReturn(...);
...
}
}
That's the main selling point of dependency injection: it makes your code testable.
I do something like that for mocking static Util classes with jMockit.
public class UtilsTest {
#After
public void teardown() {
Mockit.restoreAllOriginalDefinitions();
}
#Test
public void testMyUtil() {
Mockit.setUpMocks( MockUtil.class );
}
}
#MockClass(realClass=Util.class)
public class MockUtil{
#Mock
public static MySpecialClass someStaticMethod(int x) {
return Mockito.mock(MySpecialClass.class);
}
}

Can I test code that uses introspection with Mockito?

I'm writing unit tests for a block of code that uses introspection; specifically it calls getDeclaredField() on the class I want to mock and tries to get the value of the field. Is there a way to mock this with Mockito?
Mockito operates using the same introspection libraries you're trying to fool by creating a Mock. Even if you could cajole it to work, I'm not sure how easy it would be to understand or maintain.
I'd suggest creating a very small nested class and operating on it normally:
public class YourTest {
private static class SampleClass {
String field1;
int field2;
}
#Test public void introspectionWorks() {
yourSUT.process(new SampleClass());
}
}
Barring that, extract the difficult-to-mock call into a method you can stub easily:
public class YourSUT {
/* ... */
/* package */ Class<?> getFieldType(Object object, String fieldName) {
return object.getClass().getDeclaredField(fieldName).getType();
}
}
public class YourTest {
#Test public void introspectionWorks() {
YourSUT spy = Mockito.spy(yourSUT);
doReturn(String.class).when(spy).getFieldType(myObject, "someStringField");
}
}

Categories

Resources