How to inject mock collection by annotation with Mockito - java

I have create one parameterized class that takes two params. One is type of string and another is type of List of Abstract class. Class constructor looks like below code.
public TestService(Tenant tenant, List<AbstractService> testServices) {
testServicesMap = testServices.stream().collect(Collectors.toMap(AbstractService::getType, Function.identity()));
}
now I want to write Junit test case for this class and for that I have following piece of code.
#Mock
protected Tenant tenant;
#Mock
private List<AbstractService> testServices;
#InjectMocks
private TestService testService;
#Before
public void setup() {
testServices.add(new JobService(new JobEventService()));
testServices.add(new ApplicationService(new ApplicationEventService()));
testServices.add(new UserService(new UserEventService()));
// notificationService = new NotificationService(tenant, notificationServices);
// MockitoAnnotations.initMocks(notificationService);
}
I also tried to enabled two commented lines but its now working. Following is error that system throw on start.
org.mockito.exceptions.base.MockitoException:
Cannot instantiate #InjectMocks field named 'notificationService' of type 'class com.test.TestService'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : `null`.
Could someone help on this ?

you are mixing mocks with real objects, because you create a mock of list but then call add method on that list and then you expect stream() to work as usually.
Mockito mocks don't do anything by default so you have to tell it:
Mockito.when(testServices.stream())
.thenReturn(Stream.of(new JobService(new JobEventService())));
or better in your case is to remove #Mock from testServices and assign it a new ArrayList

The problem is that you try to mock the list, and list.stream() is called, which in the mock default returns null.
A common solution from the duplicate questions is to use a #Spy of the list.

Related

How to test init function with #Postconstruct and map inside with junit mockito

I have a class to test but i dont know how to test it. Can somebody help for test?
#Component
public class KvkkCorrBankingExecuter {
private final Map<String, IKvkkCorrBankingExecuter> operationMap = new HashMap<>();
IKvkkCorrBankingExecuter executer;
#Autowired
DemandBoeExecuter demandBoeExecuter;
#Autowired
DemandCleanBaExecuter demandCleanBaExecuter;
#Autowired
DemandGuaranteeExecuter demandGuaranteeExecuter;
#Autowired
DemandLcExecuter demandLcExecuter;
#Autowired
DemandSlcExecuter demandSlcExecuter;
#PostConstruct
public void init() {
operationMap.put("DEMAND_BOE", demandBoeExecuter);
operationMap.put("DEMAND_CLEAN_BA", demandCleanBaExecuter);
operationMap.put("DEMAND_GUARANTEE", demandGuaranteeExecuter);
operationMap.put("DEMAND_LC", demandLcExecuter);
operationMap.put("DEMAND_SLC", demandSlcExecuter);
}
}
Map line and the init function are red highlighted in the covarage. They need to be tested.
I wont give a readymade answer, but some guidance. I would advice you to try it out, that is the only way to learn and remember.
How to write unit test for this class ?
The goal of the unit test would be to test all possible scenarios. The goal should not be just to make the code coverage report red, but to avoid any possible bugs in that code for various data conditions.
Since you are testing through jUnit, do following:
Create a test class - give class name such that it indicates what class is being tested. e.g. KvkkCorrBankingExecuterTest.java
Write a method with name that says what condition you are testing.
e.g. testInitFunction()
Since you are not using spring for test, the #Postconstruct annotated method won't be called automatically.
Because the test does not use spring, the autowired attributes will be null.
For that, create Mock variables with exact same definition as the class being tested.
Then do following:
Class KvkkCorrBankingExecuterTest{
//other mock variables similar to demandLcExecuter
#Mock
DemandLcExecuter demandLcExecuter;
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
#Test
public void testInitMethod(){
// 1. Create an instance of KvkkCorrBankingExecuter
// 2. Call init() method on that instance
// 3. Validate that the size of operationMap is 5
// 4. Validate that you get values corresponding to each key. The value will be // equal to the mock attributes in this class.
}
}
Other code suggestions:
Make attributes private.

Mocking ReentrantReadWriteLock in JUnit with mockito

In my implementation class I have a read write lock definition as follows,
#Inject
#Named("CustomizedLock")
private ReentrantReadWriteLock rwLock;
I'm using it in a method named run() as,
rwLock.writeLock().lock();
to lock the process. But when I'm trying to test this with mockito I found ReentrantReadWriteLock is initialized. But when I'm trying to get rwLock.writeLock() it's null. Here is my test.
#Mock
private ReentrantReadWriteLock feedReadWriteLock;
#InjectMocks
private CustomModule module = mock(CustomModule.class);
/////////////////////////
#Test
public void test() {
when(module.getReadWriteLock()).thenReturn(mock(ReentrantReadWriteLock.class));
PowerMockito.doReturn(new ReentrantReadWriteLock()).when(module.getReadWriteLock());
cacheJob.run();
}
As I said rwLock.writeLock() is null but rwLock is initialized. Please explain how this happens with mockito. And what is the ideal way to do this?
You are getting mocking wrong:
#Mock
private ReentrantReadWriteLock feedReadWriteLock;
The above creates a mock that you then somehow have to get into your class under test.
But this:
#InjectMocks
private CustomModule module = mock(CustomModule.class);
is bogus. The InjectMocks annotation exists to do that "getting it into" part for you.
In other words, you should be doing something like:
#Mock
private ReentrantReadWriteLock feedReadWriteLock;
#InjectMocks
private CustomModule module = new CustomModule();
for example. In other words: you do not mock an instance of your class under test. You create a "real" instance - and then you have to "insert" the required mock objects into that real instance. There is absolutely no point in mocking the class under test. Because you want to test your code, not something that the mocking framework mocked for you.
The InjectMocks annotation tries to do that for you (using reflection and all kinds of black magic). Unfortunately when it can't do its job, it just silently fails.
In that sense, the answer is: don't just blindly use stuff. You have to fully understand each and any line of code that you write down. Thus: read this to understand the difference between these annotations.
And just for the record: please note that you also have to either use the Mockito JUnitRunner or to manually call Mockito.initMocks() in order have the annotations do their magic.
If you want to mock the class under test, you should use #Spy.
#RunWith(MockitoJUnitRunner.class)
public class CustomModuleTest {
#Mock
private ReentrantReadWriteLock feedReadWriteLock;
#Spy
#InjectMocks
private CustomModule module;
#Test
public void test() {
doReturn(feedReadWriteLock).when(module).getReadWriteLock();
cacheJob.run();
}
}
Note that the syntax is a bit different with a spy than with a mock. The spy allows your to instantiate the real object, but mock some methods as you wish.
Here, I return feedReadWriteLock, which is annoted with #Mock, this way, you may be able to change its behavior. You don't want to return a new instance like you did in your example.

Mock a DAO class and a method within it

I am trying to mock a DAO class that has a method which returns a list of a specific class.
private List<SpecificClass> getInfo(){
List<SpecificClass> returnInformation = dao.list(ParamOne, Param Two, SpecificClass.class);
}
The dao mentioned in the above method refers to another class.
I begin by mocking that DAO class.
Mockito.mock(TheDaoClass.class);
and creating a mocked list
private #Mock List<SpecificClass> returnedList = new ArrayList<SpecificClass>();
Then I make call to that method
dao.list(ParamOne, Param Two, SpecificClass.class);
and specify what needs to be done when it is called
when(dao.list(ParameterOne, anyString(), SpecificClass.class)).thenReturn(returnedList);
When I do the above I get a null pointer exception. There can be two causes:
I understand the list is empty but all it is supposed is hold SpecificClass's five values but that shouldn't throw an error at this point.
I think object dao is not getting mocked properly. I am only mocking the whole class Mockito.mock(TheDaoClass.class) in order to mock any object asociated with that class. I think that it is not achieving the objective. how do I go about solving this problem? Any help is appreciated. Thanks.
Make your mocked DAO object a property of your test class like so:
#Mock
private TheDaoClass mockDaoClass;
Then, in your setUp() method at the beginning of your test class call initMocks:
#BeforeClass
public void setUp() {
MockitoAnnotations.initMocks(this);
}
This should prevent the NullPointer.
Additionally, I recommend that rather than mock the List object (if you are mocking any Java library data type you are probably doing it wrong), you should create a list and populate it.
List<SpecificClass> list = new ArrayList<SpecificClass>();
list.add(new SpecificClass());
Then return the list from the mocked method.
when(mockDaoClass.list(anyString(), anyString(), SpecificClass.class)).thenReturn(list);

Why Cannot I use Mock and InjectMocks together?

valid construction:
#InjectMocks
SomeClass sc = mock(SomeClass.class);
Invalid construction:
#InjectMocks
#Mock
SomeClass sc;
I want to inject mocks to another mock. I want to use only annotation style.
Why was in Mockito forbid second construction ?
Update
example:
public class ArrTest {
private SomeClass someClass;
public List<String> foo(){
anotherMethod(); // I suppose that this method works. I want to test it separately.
//logic which I need to test
return someClass.doSmth();// I suppose that this method works. I want to test it separately.
}
public void anotherMethod(){
///...
}
}
public class SomeClass {
public List<String> doSmth(){
return null;
}
}
test:
public class ArrTestTest {
#InjectMocks
ArrTest arrTest = Mockito.mock(ArrTest.class);
#Mock
SomeClass someClass;
#Test
public void fooTest(){
Mockito.when(someClass.doSmth()).thenReturn(new ArrayList<String>());
Mockito.doNothing().when(arrTest).anotherMethod();
System.out.println(arrTest.foo());
}
}
It sounds like you're trying to do something that doesn't really make sense. You shouldn't need to inject any dependencies into your mock since mocks by definition don't have any behaviour until you define it with when(mock.someMethod()).thenAnswer() or some variation.
(except perhaps if you're using a spy(), but you've specifically said you're using a #Mock).
Maybe you could explain your use case and why you're trying to inject dependencies into a mock?
#InjectMocks specifically indicates that the annotated field will NOT contain a mock. Annotating #InjectMocks #Mock is not just unsupported—it's contradictory.
To return stubs wherever possible, use this:
#Mock(answer=Answers.RETURNS_DEEP_STUBS)
YourClass mockYourClassWithDeepStubs;
But heed the official documentation for this Answer:
WARNING: This feature should rarely be required for regular clean code! Leave it for legacy code. Mocking a mock to return a mock, to return a mock, (...), to return something meaningful hints at violation of Law of Demeter or mocking a value object (a well known anti-pattern).
Good quote I've seen one day on the web: every time a mock returns a mock a fairy dies.
A mock doesn't have any real implementation. #InjectMocks would try to find and call setters for whatever mock objects have already been created and pass them in. Mockito "knows" that this is kinda pointless on a mock, since there won't be any way to get the mock objects back out, much less do anything meaningful with them.

Mocking a Private Variable that is Assumed to Exist

How can you get a mock object in at runtime when it is not created/initialized in the class you are testing, it is not static (singleton pattern), or you don't have some sort of test constructor to hook into?
In a class that I am writing some unit testing for, I have come across a scenario I haven't encountered/solved yet. I have a JMS resource (a QueueConnectionFactory for reference, but it shouldn't matter), that is a private variable of the class I am testing. Since it has the javax.annotation.Resource annotation, at runtime it is assumed to be available. During testing, it is not, which creates the need for mocking this object.
It is not a static class and is not being used in a static way, if it was I could easily mock using the various static mocking methods I have run into. Since the resource is never created locally (in a constructor or even in a test constructor), I have no way of passing in a Mock object so that at runtime of the test, the mock is used instead of the actual object. How can I mock this Resource so that when the test executes, it will be used in place of the private #Resource object in the class I am testing?
For reference, the code is calling createConnection() on the QueueConnectionFactory which is throwing a null pointer exception since the Factory has not been initialized/mocked.
#Stateless
public class Example{
#Resource(name = "jms/exampleQCF")
private QueueConnectionFactory queueFactory;
...
public void testMe(){
Connection connection = queueFactory.createConnection();
...
}
}
After a lot more hunting around and looking at all the options Mockito/Powermock had to offer, I found the solution (which I will share in case others run into this same issue).
When you have private member variables that are never initialized (and just assumed created in other places), you can use the #InjectMocks annotation to "inject" Mocks you want into your class you are testing.
Add a variable in your test class for the class you are testing, and give it the annotation #InjectMocks (org.Mockito.InjectMocks).
Use #Mock annotations to setup the mocks you want to inject. Use the #Mock (name = "privateVariableNameHere") name property to map the Mock object to the private variable inside your class you are testing.
In either a setup function or before you call your class, initialize the mocks. The easiest way I have found is to use a "setup" method with the #Before annotation. Then inside there call MockitoAnnotations.initMocks(this); to quickly initialize anything with the #Mock annotation.
Define your Mock functionality in your test method (before calling the method you are testing).
Using the #InjectMock object, call your method you are testing... the mocks SHOULD be hooked in and working as defined in the earlier steps.
So for the example class I use above, the code to test/mock would have Connection returned as a mock which you can do whatever with. Based on the example above in my question, this is what the code would look like:
#RunWith(PowerMockRunner.class)
#PrepareForTest({/* Static Classes I am Mocking */})
public class ExampleTest {
#Mock (name = "queueFactory") //same name as private var.
QueueConnectionFactory queueFactoryMock;
#Mock
Connection connectionMock; //the object we want returned
#InjectMocks
Example exampleTester; //the class to test
#Before
public void setup(){
MockitoAnnotations.initMocks(this); // initialize all the #Mock objects
// Setup other Static Mocks
}
#Test
public void testTestMe(){
//Mock your objects like other "normally" mocked objects
PowerMockito.when(queueFactoryMock.createConnection()).thenReturn(connectionMock);
//...Mock ConnectionMock functionality...
exampleTester.testMe();
}
}
Several approaches here:
ReflectionTestUtils of Spring Testing framework: ReflectionTestUtils.setField(objectToTest, "privateFieldName", mockObjectToInject);. With this you don't introduce another dependency.
org.mockito.internal.util.reflection.FieldSetter.
PowerMock.Whitebox.setInternalState() to mock a private field.
If you need to mock internal local variable creation, use PowerMockito.whenNew(Foo.class).withNoArguments().thenReturn(foo);. Very, very useful. Cannot find other ways to do the same.
With only Mockito you cannot mock local variable creation, because when(any(Foo.class) does not work; will return null. It compiles but does not work.
References:
Mockito: Mock private field initialization

Categories

Resources