How to mock a map in mockito? - java

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;

Related

HashMap doesn't add values after #InjectMocks. The hashmap is inside class with the annotation

The problem is that nothing is added to my cache. My class is much bigger so I provide here to minimum example that should reproduce the problem.
Let's say I have a dictionary class, which uses some initialService to return hashMap with initial values.
public class Dictionary() {
#Inject
private InitialService initialService;
private Map<String, String> map;
public Map<String, String> constructMap() {
HashMap<String, String> initialMap = initialService.getHashMap("initialKey", "initialValue");
return initialMap;
}
public void saveConstructedMap() {
map = constructMap();
}
public Map<String, String> getMap() {
return map;
}
}
Then I have a test with mockito. So firstly I save the map with method saveConstructedMap() then I get the map with getMap() and then I add there value.
I would expect the value to be there but the map is empty.
Even if I don't save it to new value but will do the put on getMap() so getMap().put(...)
public class DictionaryTest() {
#Mock
private InitialService initialService;
#InjectMocks
private Dictionary dictionary;
public void test() {
dictionary.saveConstructedMap();
HashMap<String, String> myMap = dictionary.getMap();
myMap.put("key","value");
assertTrue(myMap.containsKey("key")); //returns false (the entry is not added)
}
}
From what I understand the Mock just mocks the class so its empty inside, but #InjectMocks injects the specified mock and creates an object but in normal way (like I would do it with constructor for the Dictionary. So all the methods and fields should behave as in normal class, not test one. Did i misunderstand something here?)
Does anyone know what should i do to achieve what i want?
Of course i have initMocks(this) in the setUp() method which is annotated with #Before,
Actually, DictionaryTest can't be compiled, e.g. because of HashMap<String, String> myMap = dictionary.getMap(); line (should be Map<String, String>). Probably you've written it just for the question.
Nevertheless, the main idea of mock testing is to provide a custom implementation of mocked class' methods. In this case, you should do it for the getHashMap method of InitialService mock. The example is below:
Map<String, String> initialMap = new HashMap<>();
initialMap.put(initialKey, initialValue);
Mockito.when(initialService.getHashMap("initialKey", "initialValue")).thenReturn(initialMap);
If you don't do that, Mockito will set the default value as a result of the method (in this case, it would be null):
By default, for all methods that return a value, a mock will return either null, a primitive/primitive wrapper value, or an empty collection, as appropriate.
Another approach is to make a partial mock and use real implementations of its methods where needed. But don't take advantage of it.

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

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

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 deal with test class who is having dependency on abstract method using junit mockito in java

I am new to junit testing using mockito in java. I have been stuck at one point.
I have one abstract class AbstractA which needs to test.
Implementation of AbstractA as below.
public abstract class AbstractA implements ADao {
#Autowired
NamedParameterJdbcTemplate jdbcTemplate;
#Override
public List<String> getColumns(Set<String> ids) {
String sql = query();
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("ids", ids);
return jdbcTemplate.query(sql, paramMap, rowMapper());
}
abstract protected String query();
abstract protected AbstractIpRowMapper rowMapper();
}
And a test class for above is AbsractATest
public class AbsractATest {
#InjectMocks
AbsractA abstractA;
#Mock
NamedParameterJdbcTemplate jdbcTemplate;
#Mock AbstractIpRowMapper abstractIpRowMapper;
#Before
public void setUp() throws IOException, SQLException {
abstractA=Mockito.mock(AbsractA.class, Mockito.CALLS_REAL_METHODS);
jdbcTemplate=mock(NamedParameterJdbcTemplate.class);
List<String> idsinput=new ArrayList<String>();
idsinput.add("123");
idsinput.add("124");
idsinput.add("125");
Set<String> ids=new LinkedHashSet<String>();
ids.add("123");
ids.add("124");
ids.add("125");
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("ids", ids);
String query="select ids from tableA where ids=:ids";
when(abstractA.query()).thenReturn(query);
when(jdbcTemplate.query(query, paramMap,rowMapper())).thenReturn(idsinput);
org.springframework.test.util.ReflectionTestUtils.setField(abstractA, "jdbcTemplate", jdbcTemplate);
}
protected AbstractIpRowMapper rowMapper() {
return absractIpRowmapper;
}
But after running this test case I am getting empty value for
abstractA.getColumns();
Please help me to understand what I should need to do in above case.
Run doCallRealMethod().when(abstractA).getColumns(); in the unit test
You don't need to test abstract class tdd knows nothing about abstract classes, make it normal class and only you have same code duplication with two or more class lift it up to abstract, test for this class will not change. Specify sql query string and IPRowMapper as constructor parameters this simplify and make your code more clean. Second, you don't need such complicated setup for tests, you need only to verify interactions, not return value, verify only NamedParameterJdbcTemplate mock, whats values passed to it.

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