Mockito Spying on Class that has an internal method reference - java

I'm seeing a different in behaviour when spying on a service using the #Spy annotation and having Mockito create the Server verses explicitly calling the constructor.
public class MyService {
private final Supplier<String> methodBCall;
public MyService() {
methodBCall = this::methodB;
}
public void methodA() {
methodBCall.get();
}
public String methodB() {
return "methodB";
}
}
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Spy
private MyService myService1;
#Spy
private MyService myService2 = new MyService();
#Test
public void testSucceeds() {
myService1.methodA();
verify(myService1, times(1)).methodA();
verify(myService1, times(1)).methodB();
}
#Test
public void testFails() {
myService2.methodA();
verify(myService2, times(1)).methodA();
verify(myService2, times(1)).methodB();
}
}
The failing test fails with
Wanted but not invoked:
myService2.methodB();
-> at com.phemi.services.policy.impl.MyTest.testFails
Why do these two behave differently? What is Mockito doing to initialize myService1 that enables it to spy on methodB?
This is a simplified example, in my case to test my service properly I need to call its constructor with an argument (and so cannot use the #Spy with a default constructor). However, when I do that I cannot properly verify method calls.

The spy on myService2 is only created after the object has been constructed, so having a method call in the constructor is not helpfull as it contains a method reference to the initial object (which is not the spy object).
The difference becomes more evident when you compare the implementation for both cases:
Mockito.spy(Class)
public static <T> T spy(Class<T> classToSpy) {
return MOCKITO_CORE.mock(classToSpy, withSettings()
.useConstructor()
.defaultAnswer(CALLS_REAL_METHODS));
}
Mockito.spy(Object)
public static <T> T spy(T object) {
return MOCKITO_CORE.mock((Class<T>) object.getClass(), withSettings()
.spiedInstance(object)
.defaultAnswer(CALLS_REAL_METHODS));
}
As you can see the first case, based on a class (which is used if no instance for #Spy was created), creates a mock first and uses the constructor on the mocked object.
In the second case the constructor is not considered instead a different instance is created.

Related

How to mock a method which is type casted?

Class to be tested
public class KnockoutValidation {
public boolean runFormValidation(String param1, boolean param1, final String param3) {
//...
AccessBeanFactory fact = new AccessBeanFactory();
AccessBean bean = (AccessBean) fact.getAccessBean("abc", "xyz");
//....
}
}
Test Class
#RunWith(MockitoJUnitRunner.class)
public class KnockOutValidationTest {
#InjectMocks
KnockoutValidation KnockoutValidationMock;
#Mock
AccessBeanFactory factMock;
AccessBean accessBean;
#Before
public void setUp() {
accessBean = new AccessBean();
when(factMock.getAccessBean(anyString(), anyString())).thenReturn(accessBean);
}
#Test
public void doKnockoutValidationTest() {
Boolean result = KnockoutValidationMock.runFormValidation("a", true, "c");
Assert.assertEquals(result, true);
}
}
Even after mocking it is calling the actual implementation and throwing an exception and getting
java.lang.NullPointerException
ideally when we mock it should not execute actual method, here it is going into that getAccessBean method which is again a big API with a lot of try and catch blocks. So somewhere inside it is throwing an exception.
I just want to know why mocking is not working and how to mock this type of casted methods
I believe the way you had written implementation, it won't be possible reason is
AccessBeanFactory fact= new AccessBeanFactory();
instead you can
#Autowired private AccessBeanFactory fact;
Problem :- Every-time you call fact.getAccessBean with newly created object(instead of mock) while beans are not available. So it does throw NPE as expected
The #InjectMock won't work in this case because you are creating the AccessBeanFactory in place with a new constructor.
AccessBeanFactory fact= new AccessBeanFactory();;
You should have it as a field of the class, then the InjectMock will work, or better pass the factory as an argument.
Here is one example that should work. #InjectMock works by type, meaning that it will search through the class's field with Reflection and injects the mocks you specify with the #Mock annotation.
public class KnockoutValidation {
#Autowired
AccessBeanFactory fact;
public boolean runFormValidation(String param1, boolean param1, final String param3) {
//...
AccessBean bean = (AccessBean) fact.getAccessBean("abc", "xyz");
//....
}
}
You could also try to use PowerMockito's whenNew that will actually apply to the inline class creation, but that's a dark path you should avoid and only use with 3rd party codes.

How to Unit Test A Method Argument which is a Builder Class in Mockito?

I have a dependency in the Spring Boot which is called from my class. This dependency makes a call with a newly instantiated builder pattern class as an argument. I need to know if it is possible to verify if this single builder class was constructed with certain values when the dependency call is made, e.g.:
public class MyClass {
#Autowired
private MyDep myDep;
public void callMyDepService() {
myDep.serviceCall(new MyBuilder().paramOne("One").paramTwo("Two").build());
}
}
As you can see, a new MyBuilder is instantiated every time, so I can't just use Mockito's eq() to match the arguments' value.
I would like to make sure callMyDepService calls myDep.serviceCall with certain parameter values.
Using a captor seems to be the easiest way to do that.
Something like this, where SomeClass is the class your MyBuilder builds.
#ExtendWith(MockitoExtension.class)
public class CaptureTest {
#InjectMocks
MyClass classUnderTest;
#Mock
MyDep myDep;
#Test
public void test() {
classUnderTest.callMyDepService();
Captor<SomeClass> captor = ArgumentCaptor.forClass(SomeClass.class);
Mockito.verify(myDep).serviceCall(captor.capture());
SomeClass parameter = captor.getValue();
// do assertions
}
}

PowerMock static method mocking isn't taken into account for each #InjectMocks invocation

I want to write some unit tests, that use JUnit 4.12, Mockito 1.9.5 and PowerMock 1.6.1.
The class has some fields annotated with #Mock, as well as some fields annotated with #InjectMocks.
The attribute that is annotated with #InjectMocks reaches at some point a parent constructor which contains some static method invokation, that should be mocked with PowerMock.
The problem is the first test works seamlessly, while the second test does not seem to mock the static methods at all.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ StaticClass.class })
public class TestClass {
#Mock
private SomeClass attribute1;
#InjectMocks
private SomeOtherClass attribute2;
#BeforeClass
public static void setUp() {
PowerMockito.mockStatic(StaticClass.class);
when(StaticClass.staticMethod(any(), any()).thenReturn(new SomeConcreteClass());
}
#Test
public void test1() {
assertEquals(attribute2.method1(), value1);
}
#Test
public void test2() {
assertEquals(attribute2.method2(), value2);
}
}
public class SomeOtherClass {
private SomeClass attribute;
public SomeOtherClass() {
SomeConcreteClass value = StaticClass.staticMethod(argument1, argument2);
value.someOtherMethod();
}
}
As mentioned before, the first test passes and the StaticClass.staticMethod() is mocked as expected by PowerMock.
The second test does not pass and it throws a NullPointerException at line when someOtherMethod is called on value (because value = null, as the StaticClass.staticMethod was not mocked anymore by PowerMock).
As explained in (Mocking behaviour resets after each test with PowerMock) Powermock resets the mocks before each test.
For some reason it works the first time - there exists
an unresolved bug report for that issue (https://github.com/powermock/powermock/issues/398).
Its arguably bad design, but a way to do what you want is the following:
Instead of relying on the annotation set up the mocks manually.
private SomeClass attribute;
private SomeOtherClass testClass;
#Before
public void setUp() {
PowerMockito.mockStatic(StaticClass.class);
Mockito.when(StaticClass.staticMethod(anyString())).thenReturn(new SomeConcreteClass());
attribute = Mockito.mock(SomeClass.class);
testClass = new SomeOtherClass();
// assign mock manually
testClass.attribute = attribute;
}
The prefered way would be to supply the attribute using the constructor of SomeOtherClass, however since you seem to use a empty constructor
you will have to set the value from the outside. If the attribute instance is not accessible you might be forced to use reflections.
The cleaner way would be to refactor the constructor of you SomeOtherClass to not use a static method inside. Instead passing SomeConcreteClass as a parameter to the constructor is the way to go.
Some people even say you should not have any logic inside of a constructor.

How can I test if a method was called on an object created inside the method to be tested

Is it possible to test that the "innerMethod" was called without modifying the Class class?
I need to make a unit test in a separate class both scenario of the "someCondition".
The problem is that the method is void so I cannot make use of the return type. The only way would be to check if the "innerMethod" was called.
I was thinking to use Mokito verify but this method is called inside a method on an object created at runtime.
Any suggestion is most welcome.
public class Class {
public void outerMethod(outerObj) {
if(someCondition) {
Object innerObj = new Object();
innerObj.innerMethod(outerObj);
} else {
//other code
}
}
You can achieve that with the use of Mockito::times and Mockito::verify methods.
test setup would be as follows:
#InjectMocks
private SomeService service;
#Mock
private SomeHelper helper;
and then test that some method from the helper has been involved in the following manner:
#Test
public void testInnerHasBeenCalledOnce() throws Exception {
service.outherMethodName(someParam);
Mockito.verify(helper, Mockito.times(1)).innerMethodName(someParamSecond);
}

Why is my stubbed method returning null?

I have a class Dummy. I inject 3 variables. However, one of them is not injectable because it is an interface. So I inject an object, one of whose methods return the needed type.
Class Dummy
{
private final Class1 class1;
private final Class2 class2
private final Interface1 interface1;
#Inject
Dummy(Class1 class1, Class2 class2, HelperClass helperclass)
{
this.class1 = class1;
this.class2 = class2;
this.interface1 = helperclass.somefunction();
}
}
The HelperClass's somefunction returns an instance of Interface1.
This is my test:
#RunWith(MockitoJUnitRunner.class)
Class DummyTest
{
#Mock
private Class1 class1;
#Mock
private Class2 class2;
#Mock
private HelperClass helperclass;
#InjectMocks
private Dummy dummy;
#Before
public void start()
{
Interface1 mockInterface = mock(Interface1.class);
when(helperclass.somefunction()).thenReturn(mockInterface);
}
#Test
public void test()
{
// etc...
}
}
However, interface1 is null when I run the test. What am I doing wrong?
#InjectMocks happens before the #Before annotation.
For this reason (and other reasons), I recommend not using #InjectMocks at all; just build your SUT class in the #Before method with a real constructor.
This ordering is obvious when you add a few print statements to your test class. I removed all the Class1 and Class2 stuff as it's not relevant. See this code run:
#RunWith(MockitoJUnitRunner.class)
public class DummyTest {
#Mock
private HelperClass helperclass;
#InjectMocks
private Dummy dummy;
#Before
public void start()
{
System.out.println("In #Before!");
Interface1 mockInterface = mock(Interface1.class);
when(helperclass.somefunction()).thenReturn(mockInterface);
}
#Test
public void test()
{
System.out.println("In #Test!");
}
public static class Dummy {
public final Interface1 interface1;
public final HelperClass helperclass;
#Inject
Dummy(HelperClass helperclass)
{
System.out.println("In dummy constructor!");
this.interface1 = helperclass.somefunction();
this.helperclass = helperclass;
}
}
private static class HelperClass {
Interface1 somefunction() {
return new Interface1() {};
}
}
private static interface Interface1 {
}
}
Output:
In dummy constructor!
In #Before!
In #Test!
If you insist on doing it with #Mock and #InjectMocks, you could try using the answer argument instead:
#Mock(answer=Answers.RETURNS_MOCKS)
will make helperclass.somemethod() return a mock instead of null.
Honestly, it's not surprising that it works this way. The authors of Mockito really don't like Partial Mocks / Stubs, and explicitly say so in their documentation:
As usual you are going to read the partial mock warning: Object oriented programming is more less tackling complexity by dividing the complexity into separate, specific, SRPy objects. How does partial mock fit into this paradigm? Well, it just doesn't... Partial mock usually means that the complexity has been moved to a different method on the same object. In most cases, this is not the way you want to design your application.
However, there are rare cases when partial mocks come handy: dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.) However, I wouldn't use partial mocks for new, test-driven & well-designed code.
Having helperclass return something other than null is a partial mock, and therefore they won't like it.

Categories

Resources