how to captor a hashmap inside a nested method in Mockito? - java

The class and its methods as follows.
Class MyClass{
method1(){
method2(para1)
}
method2(para1){
HashMap<String,String> users=new HashMap<>();
...
para1.setUsers(users)
}
}
I want to captor the users hashmap for unit testings by mocking the MyClass. How I can complete this with mockito?

Assuming para1 is either a #Mock or a #Spy along the lines of:
#Mock
private Para1Type para1;
// or
#Spy
private Para1Type para1 = new Para1Type();
then you can use a simple ArgumentCaptor
#Captor
private ArgumentCaptor<Map<String, String>> usersCaptor;
And then use verify() inside your test:
// call the method under test
myClass.method2(para1);
// verify the call took place
verify(para1).setUsers(usersCaptor.capture());
// extract the users
Map<String, String> users = usersCaptor.getValue();
// do something with users

Related

Unit Test: Cannot use ArgumentCaptor

I am trying to create a unit test for the following method that calls another private method:
public CommandDTO create(final LabelRequest request) {
return saveLabel(new Label(), request);
}
private CommandDTO saveLabel(final Label label, final LabelRequest request) {
label.setName(request.getName());
final Label saved = labelRepository.saveAndFlush(label);
return CommandDTO.builder().uuid(saved.getUuid()).build();
}
It returns "nullpointer exception for the saved parameter as I did not mock in in my test.
Here is the Unit Test. I added 2 question as comment (Q1 and Q2). Could you please clarify me what is wrong?
#RunWith(MockitoJUnitRunner.class)
public class LabelServiceImplTest {
#Mock
private LabelRepository labelRepository;
#InjectMocks
private LabelServiceImpl labelService;
#Captor
ArgumentCaptor<Label> labelCaptor;
#Test
public void test_create {
// Q1: I am not sure if the following parts are needed
final LabelRequest request = new LabelRequest();
request.setName("Label Name");
final Label label = new Label();
label.setName(request.getName());
// Q2: I think there is no need to mock saveAndFlush method.
// But in this scene it returns "nullpointer exception"
when(labelRepository.saveAndFlush(any())).thenReturn(label);
CommandDTO result = labelService.create(request);
Mockito.verify(labelRepository).saveAndFlush(labelCaptor.capture());
final Label value = labelCaptor.getValue();
// then make necessary assertions
}
}
F I R S T
I think that you only declared your mocks but never defined/created them. There's basically three ways to do so:
1) mockito extension
The convenient way in JUnit 5 is to use the MockitoExtension:
#ExtendWith(MockitoExtension.class)
public class LabelServiceImplTest {
// declare mocks, spies and captors ...
// system under test
#InjectMocks
LabelService sut;
}
Nothing else should be needed now.
Mind that by #InjectMocks you instruct Mockito to create your system under test and inject the mocks. You may as well do that manually, e. g. by injecting mocks into the SUT's constructor. I prefer that way to have more control over the configuration of my SUT.
2) MockitoAnnotations.openMocks(testclass)
This method will inject mocks into the given object:
public class LabelServiceImplTest {
// declare mocks, spies and captors ...
// system under test
#InjectMocks
LabelService sut;
#BeforeEach
void setup() {
MockitoAnnotations.openMock(this)
// ...
}
}
On JUnit 4 you'd use MockitoAnnotations.initMocks(…) instead.
3) the old school way
public class LabelServiceImplTest {
LabelRepository labelRepositoryMock = Mockito.mock(LabelRepository.class);
// ...
// system under test
LabelServiceImpl sut;
#BeforeEach
void setup() {
sut = new LabelService(labelRepositoryMock);
// ...
}
}
S E C O N D
Your questions …
1) Do you need to create the request and the label?
Yes. You call the service using the request and the mock returns the label. I would suggest you do not use the request's property to set up your label, use a String literal instead.
2) Do you need to mock the saveAndFlush() method?
Yes. This is the part where you configure your SUT's environment to behave in a predictable way.
You might consider postfixing your mocks, spies and captors by: "Mock", "Spy" and "Captor".
You might also consider calling your system under test "sut".
#Mock
private LabelRepository labelRepositoryMock;
#Captor
ArgumentCaptor<Label> labelCaptor;
// system under test
#InjectMocks
private LabelServiceImpl sut;
This makes the test code more readably, I think.

How to mock #Inject Api-Class with Mockito

I'm trying to test a Java method with Junit,
Unfortunately I can't get any further at one point because the Api class was defended as #Inject
I actually tried everything I could, unfortunately null is always returned and the test fails every time.
#Inject
private MemberAPi memberApi;
NewMember newMember = new NewMember();
newMember = MemberApi.addMember(new CreateMemberParameterObj (newMember, getId , false, Obj ))
Test: I try to mock it like that e.g.
#Mock
private MemberAPi mockedMemberApi;
when(mockedMemberAPi.addMember(anyObject())).thenReturn(anyObject());
Mock the MemberAPI and the NewMember classes.
Use #InjectMocks and Mockito will automatically inject the mockMemberAPI object.
Here is some code:
#InjectMocks
private Blam classToTest; // your class.
#Mock
private MemberAPi mockMemberAPi;
#Mock
private NewMember mockNewMember;
#Before
public void before()
{
MockitoAnnotations.openMocks(this);
doReturn(mockNewMember).when(mockMemberAPI).addMember(anyObject());
}
I use the doReturn().when().xxx();
pattern instead of the
when(mockedMemberAPi.addMember(anyObject())).thenReturn(mockMemberAPI);
pattern.
Note:
thenReturn(anyObject()); makes no sense because you can't return anyObject().

How to mock a map in mockito?

I have two maps that have the same arguments. I would like to mock one of them to test my class. But I don't know a reason that it's not working
this is my class
public class A {
private Map<String, Foo> map1;
private Map<String, Foo> map2;
public A() {
this.map1 = new HashMap<String,Foo>();
map1.put("one",new Foo());
this.map2 = new HashMap<String, Foo>();
map2.put("two", new Foo());
}
public void doSomenthing(String str){
Foo foo = map1.get(str)
//other actions
}
}
and this is my test class:
public class ATest{
#InjectMocks
private A a;
#Mock
private HashMap<String, Foo> mapTest;
#Before
public void initialize() throws Exception {
when(mapTest.get(Mockito.anyString())).thenReturn(new Foo());
}
#Test
public void testSomething() throws Exception {
a.doSomething("blabla");
}
}
#InjectMocks tries to inject the dependencies in following ways
By using construtor first.
Then property setter.
Then field injection.
#3 is probably the way for you. Try the following:
Remove map initialization from constructor to their setter function.
Change the variable name mapTest to map1 in your test class.
also define map2 similarly.
Then InjectMocks should find a matching field to inject.
Share more parts fo the code for a more precise answer.
Before you jump in mock the Map, is that necessary to mock a map? Mock is used to replace other part of your code that you don't want to be involved in your unit test. While Map is easy enough to initiate in unit test.
You need the same name and same type in the two classes:
//main class
private HashMap<String, Foo> map;
//test class
#Mock
private HashMap<String, Foo> map;

How to deal with side effects of mocked method with JUnit/Mockito

This might be a dumb question or something obvious to figure out, but nevertheless, I'm really struggling to solve this.
Let's say we have the following logic within a method under test:
#Service
public class ServiceToTest() {
#Autowired
private SomeService someService;
public String testMethod() {
Map<String, String> parameters = new HashMap<String, String>();
// eventParameters will be populated inside someService
String result = someService.doLogic(parameters);
// do something with the result here that doesn't really matter for this example
String name = parameters.get("name").toLowerCase();
return name;
}
}
Inside SomeService the parameters map is populated with some values, like the "name" in this example. I would like to mock this service in my unit test.
Consider the following unit test snippet:
#RunWith(SpringRunner.class)
public class ServiceToTestTest {
#TestConfiguration
static class ServiceToTestConfiguration {
#Bean
public ServiceToTest serviceToTest() {
return new ServiceToTest();
}
#Autowired
private ServiceToTest serviceToTest;
#MockBean
private SomeService someService;
#Test
public void testShouldReturnJimmy() {
given(someService.doLogic(Mockito.anyMap())).willReturn("whatever");
String name = serviceToTest.testMethod();
assertThat(name).isEqualTo("jimmy");
}
}
When I execute this test I get a NullPointerException on this line:
String name = parameters.get("name").toLowerCase();, which makes sense as the method that should populate this map is mocked and parameters.get("name") is null. Let's also assume that I really want to have a String returned from doLogic(parameters), so it cannot be the parameters map.
Is there a way to somehow instruct the mock object to populate the parameters map, or to mock the map object itself?
(The code examples here were written for this post on the fly, so please forgive me if there are any stupid mistakes that I haven't noticed while writing them ;-) )
Can be done using the controversial thenAnswer method.
https://static.javadoc.io/org.mockito/mockito-core/2.13.0/org/mockito/stubbing/OngoingStubbing.html#thenAnswer-org.mockito.stubbing.Answer-
But JB's comment is correct. This is not a great idea.

Mockito void method how to inspect private variable?

I am trying to unit test a void method which gets data from database, formats into map and passes onto another class.
I have mocked out the database call and returned my own data, and I want to inspect the map which has been formatted contains the right number of elements and keys in right locations.
I have tried playing around with argumentCaptor to do this but struggling to get my head round it.
Method to test:
public class MyClass {
#Autowired
private Dao dao;
#Autowired
private AnotherClass anotherClass;
public void format(String, Date) {
Map<Object,Object> map = getDataAndFormat(String, Date);
anotherClass.doSomething(map);
}
private Map<Object, Object> getDataAndFormat(String, Date) {
Map map;
if (String.equals("A") {
map = dao.getData(Date);
}
else {
map = dao.getDataSomeThingElse(Date);
}
}
}
Any help much appreciated
Thanks,
so: This is what I have so far:
#InjectMocks
#Autowired
//class to test
private MyClass myClass;
#Mock
Dao dao;
#Captor
private ArgumentCaptor<String> argumentCaptor;
#Captor
private ArgumentCaptor<Date> argumentCaptorB;
public void testFormat()
{
when(dao.getData(Matchers.any())).thenReturn(data());
myClass.format("A",new Date());
}
So i want to use argument captors (but not entirely sure how to) to get the map from the format method call and inspect the returned map. The code i currently have is hitting all my code but I can't assert on anything hence why i wanted to check the map contains what I expect it to. Hope that makes sense
It appears that what you want to do is to confirm the contents of the map that is passed to AnotherClass.
If AnotherClass is an interface, you can create a mock instance of AnotherClass and inject it into your MyClass. You can then verify that it has been called with your arguments of choice:
Mockito.verify(mockAnotherClass).doSomething(expectedMap);

Categories

Resources