Injecting mock initiated by InjectingMock - mockito

#InjectMocks
private Foo foo;
#Mock
private Var var;
#InjectMocks
private MyClass myClass
Foo has Var.
MyClass has Foo.
I am injectiong Var in Foo by #InjectMocks and like to inject Foo to MyClass but Foo in MyClass is null.
I guess it's because Foo is not annotated by #Mock. Is there any way I can inject Foo to MyClass while injecting Var to Foo?

Suppose your class dependency is like this:
MyClass ---dependsOn--> Foo --dependsOn--> Var
If you are writing unit tests for MyClass, you just need to mock Foo and inject into MyClass. Because Foo itself is mocked in this case, you don't need to worry about its dependencies.
#Mock private Foo foo;
#InjectMock private MyClass myClass;
To write unit tests for Foo, I'd suggest you create a separate unit test class in a separate file. There you can mock Var and inject into Foo.
#Mock private Var var;
#InjectMock private Foo foo;
To conclude, unit tests should be written for each layer of dependencies. You shouldn't mix unit tests of two layers in one test file. To unit test a class, you just need to mock its direct dependencies. So while testing MyClass, you just mock Var and simulate its behaviour as per your requirement:
Mockito.when(var.someMethod()).thenReturn(someValue);

Related

Mockito Spy behaves like Mock

Environment: Java11, AWS Lambda, Dagger, JUnit5 (5.9.1), Mockito(4.8.1) (tried both mockito core & inline)
I have classes A, B and C.
C is injected to B and B is injected to A.
Method A.ma1() calls B.mb1() and B.mb1 calls C.mc1()
I just want to verify if a method "mc1" of C is called or not if I call A.ma1
Here is my structure:
#ExtendWith(MockitoExtension.class)
class Test {
#InjectMocks
A a;
#Spy
B b;
#Mock
C c;
#Test
public void test() {
a.ma1();
verify(c).mc1(any());
}
}
The problem is when A.ma1() calls B.mb1(), B.mb1() behaves like a Mock instead of a Spy.
The contents of the method never being executed during debugging, but immediately returning. I also tried to annotate B with #InjectMocks along with #Spy. It also did not work, throwing a different kind of exception.
Does anybody have any idea why does B behave like a Mock instead of a Spy?
Added after comment:
Here is the complete code: (simplified)
AService is A, InternalService is B and PanelDao is C in the above example. B's "selectMappedInternal" never executes line by line but returns immediately like a mock when called.
#ExtendWith(MockitoExtension.class)
class Test {
#InjectMocks
AService aService ;
#Spy
InternalService internalService ;
#Mock
PanelDao panelDao;
#Test
public void test() {
..
}
}
public class AService {
#Inject
InternalService internalService;
#Inject
public AService() {
}
public void processMessage(AccSqsMessage accSqsMessage) {
..
internalSet = internalService.selectMappedInternal(accSqsMessage.getCode());
..
}
}
public class InternalServiceImpl implements InternalService {
#Inject
PanelDao panelDao;
#Inject
public InternalServiceImpl() {
}
#Override
public Set<Internal> selectMappedInternal(String code) {
..
Optional<Panel> p = panelDao.findPanelByCode(code);
..
}
}
Finally able to solve it as below.
My guess about cause of the problem is implementation class "InternalServiceImpl" for interface "InternalService" could not be injected properly to unit test class (despite it is working fine when injected to a business class), so during debugging, I was not able to see execution of methods in spy object.
After spying (without annonation) an explicitly provided implementation class, everything seems solved.
#ExtendWith(MockitoExtension.class)
class Test {
#InjectMocks
AService aService ;
#InjectMocks
InternalService internalService = Mockito.spy(InternalServiceImpl.class);
#Mock
PanelDao panelDao;
#Test
public void test() {
..
}
}

Call #Autowire bean through Mockito

I have Class A and Class B. B is autowired in class A. Now I want to test the flow using mockito.
So the problem is when I tried to mock the class A and B in my test case using #InjectMock its going to class A but its not invoking class B.
I dont want to mock the class B which is autowired in class A, from A its should make call to class B and get the user details data.
#Component
public class A {
#Autowired
private B b;
public Users getUsers() {
Long id = 10;
b.getUserDetails(id);
// some Logic
}
}
#Component
public class B {
public UserDetails getUserDetails(Long id) {
// some logic to get users details ..
}
}
#RunWith(MockitoJUnitRunner.class)
public class TestA {
#InjectMocks
private A a;
#InjectMocks
private B b;
#Test
public void testA() {
Users actual = a.getUsers();
assertEquals(actual, expected());
assertNotNull(actual);
}
private Users expected() {
return new Users(); // expected users object
}
}
You should use #Spy on B in order to use real B class
#Spy
private B b;
the spy will wrap an existing instance. It will still behave in the same way as the normal instance – the only difference is that it will also be instrumented to track all the interactions with it.
You should change #InjectMocks annotation on above B to #Spy and you should add #Spy on above A also. Because you want to use B.class's and A.class's real methods. Why you need to use #Spy ?
If you use #Mock, by default for all methods, mock returns null, an empty collection or appropriate primitive / primitive wrapper value (e.g. 0, false, null, ...)
If you use #Spy then the real methods are called (unless a method was stubbed).
As a result, your creation in TestA.class should be like :
#Spy #InjectMocks private A a;
#Spy private B b;

groovy.lang.MissingMethodException With PowerMock and Jenkins getItemByFullName

How can I use PowerMockito to ensure Jenkins static method returns my mocked object?
I see that if I have a test, that Jenkins is the mock. However, if I add what looks like a valid PowerMockito.when for an additional static method, I get the error below. I'm stumped.
error
groovy.lang.MissingMethodException: No signature of method:
static jenkins.model.Jenkins.getItemByFullName() is applicable for argument types:
(java.lang.String) values: [job]
Possible solutions:
getItemByFullName(java.lang.String),
getItemByFullName(java.lang.String, java.lang.Class)
code
#RunWith(PowerMockRunner.class)
#PrepareForTest([Jenkins.class, Job.class])
class MyTest {
def thisScript
#Mock
private Jenkins jenkins
#Mock Job job
MyClass myClass
#Before
void setUp() {
PowerMockito.mockStatic(Jenkins.class)
PowerMockito.when(Jenkins.getInstance()).thenReturn(jenkins)
PowerMockito.when(Jenkins.getItemByFullName("job".toString())).thenReturn(job)
}
A major oops on my part. The getInstance method is static, getItemByFullName is not static. So, here's the fix
#RunWith(PowerMockRunner.class)
#PrepareForTest([Jenkins.class, Job.class])
class MyTest {
def thisScript
#Mock
private Jenkins jenkinsInstance
#Mock Job job
MyClass myClass
#Before
void setUp() {
PowerMockito.mockStatic(Jenkins.class)
PowerMockito.when(Jenkins.getInstance()).thenReturn(jenkins)
PowerMockito.when(jenkinsInstance.getItemByFullName("job".toString())).thenReturn(job)
}
I must mock the instance's method jenkinsInstance.getItemByFullName and not the Jenkins.class class's static method.

Mocking two objects of the same type with Mockito

I'm writing unit tests using Mockito and I'm having problems mocking the injected classes. The problem is that two of the injected classes are the same type, and only differentiated by their #Qualifier annotation. If I tried to simply mock SomeClass.class, that mock is not injected and that object is null in my tests. How can I mock these objects?
public class ProfileDAL {
#Inject
#Qualifier("qualifierA")
private SomeClass someClassA ;
#Inject
#Qualifier("qualifierB")
private SomeClass someClassB ;
//...various code, not important
}
#RunWith(MockitoJUnitRunner.class)
public class ProfileDALLOMImplTest {
#InjectMocks
private ProfileDALLOMImpl profileDALLOMImpl = new ProfileDALLOMImpl();
#Mock
private SomeClass someClassA;
#Mock
private SomeClass someClassB;
private SomeResult mockSomeResult = mock(SomeResult.class);
#Test
public void testSomeMethod() {
when(someClassA .getSomething(any(SomeArgment.class)).thenReturn(mockSomeResult);
Int result = profileDALLOMImpl.someTest(This isn't relevant);
}
}
I have tried mocking two objects with the same type with Mockito 1.9.5 using JUnit and it works.
See: http://static.javadoc.io/org.mockito/mockito-core/1.9.5/org/mockito/InjectMocks.html
Relevant type info from the doc:
"Field injection; mocks will first be resolved by type, then, if there is several property of the same type, by the match of the field name and the mock name."
And this one which seems to say you should make the mock name match the field name for all your mocks when you have two of the same type:
"Note 1: If you have fields with the same type (or same erasure), it's better to name all #Mock annotated fields with the matching fields, otherwise Mockito might get confused and injection won't happen."
Perhaps this latter one is biting you?
Just confirmed what Splonk pointed out and it works that way in Mockito 1.9.5, as soon as I removed one of the mocked classes, it failed.
So, in your case, make sure you have both of the mocked classes with the same name as in the class in your test:
#Mock
private SomeClass someClassA;
#Mock
private SomeClass someClassB;
If you don't use annotation, you get something like
public class MyClass {
private MyDependency myDependency;
public void setMyDependency(MyDependency myDependency){
this.myDependency = myDependency;
}
}
and
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.*;
public class MyTest {
private MyClass myClass;
private MyDependency myDependency;
#Before
public void setUp(){
myClass = new MyClass();
myDependency = mock(MyDependency.class);
myClass.setMyDependency(myDependency);
}
#Test
public void test(){
// Given
// When
// Then
}
}
You can do just the same if your object has its dependencies specified via constructor rather than via setter. I guess your dependency injection framework can annotate the setters the same way you annotate private fields, but now your tests don't rely on any dependency injection framework.

Strange GWT serialization exception when overiding method of serialized object

I have a GWT serializable class, lets call it Foo.
Foo implements IsSerializable, has primitive and serializable members as well as other transient members and a no-arg constructor.
class Foo implements IsSerializable {
// transient members
// primitive members
public Foo() {}
public void bar() {}
}
Also a Service which uses Foo instance in RPC comunication.
// server code
public interface MyServiceImpl {
public void doStuff(Foo foo);
}
public interface MyServiceAsync {
void doStuff(Foo foo, AsyncCallback<Void> async);
}
How i use this:
private MyServiceAsync myService = GWT.create(MyService.class);
Foo foo = new Foo();
...
AsyncCallback callback = new new AsyncCallback {...};
myService.doStuff(foo, callback);
In the above case the code is running, and the onSuccess() method of callback instance gets executed.
But when I override the bar() method on foo instance like this:
Foo foo = new Foo() {
public void bar() {
//do smthng different
}
};
AsyncCallback callback = new new AsyncCallback {...};
myService.doStuff(foo, callback);
I get the GWT SerializationException.
Please enlighten me, because I really don't understand why.
I think the problem comes from the rpc serialization policy which creates a "white list" of serializable types for the rpc service.
In your case the "Foo" class is in the whitelist but when you override a method, you create an anonymous class that extends Foo but is not in the whitelist, so GWT refuses to serialize it... and I see no way to do what you want without creating an explicit subclass...

Resources