how to inject mock without using #injectmocks - java

I have the following class
public class One {
private Map<String, String> nodes = new HashMap<String, String>();
public void addNode(String node, String nodefield){
this.nodes.put(node, nodefield);
}
}
I want to write a test class to test the addNode method and have the following:
#RunWith(MockitoJUnitRunner.class)
public class OneTest {
#InjectMocks
private One one = new One();
#Mock
Map<String, String> nodes;
#Test
public void testAddNode(){
one.addNode("mockNode", "mockNodeField");
Mockito.verify(nodes).put("mockNode","mockNodeField");
}
}
which works. But I was wondering if there is a way to do it without using #InjectMocks like the following
public class OneTest {
private One one;
#Test
public void testAddNode(){
Map<String, String> nodes = Mockito.mock(Map.class);
one = Mockito.injectmocks(One.class, nodes); // or whatever equivalent methods are
one.addNode("mockNode", "mockNodeField");
Mockito.verify(nodes).put("mockNode","mockNodeField");
}
}

How about change the class by injecting the map as a dependency? This makes it easier to test and gives you the added benefit of being able to use an implementation of the Map interface, for example:
public class One {
private Map<String, String> nodes;
public One(Map<String, String> nodes) {
this.nodes = nodes;
}
public void addNode(String node, String nodefield){
this.nodes.put(node, nodefield);
}
}
Then to test:
Map mockMap = Mockito.mock(Map.class);
One one = new One(mockMap);
one.addNode("mockNode", "mockNodeField");
Mockito.verify(mockMap).put("mockNode","mockNodeField");

Okay I figured it out by using PowerMockito instead of normal Mockito.
public class OneTest {
private One one;
#Test
public void testAddNode(){
HashMap nodes = PowerMockito.mock(HashMap.class);
PowerMockito.whenNew(HashMap.class).withNoArguments().thenReturn(nodes);
One one = new One();
one.addNode("mockNode", "mockNodeField");
Mockito.verify(nodes).put("mockNode","mockNodeField");
}
}
However, I don't really know what PowerMockito does that Mockito doesn't do to make it work though.

Related

How to mock a return from a call to a private method

I have a class which has a method I want to test, but it calls a private method in the same class to get a Map value. I want to mock what the private method returns to the method I want to test.
import java.util.*;
public class ClassOne {
public List<String> getList(String exampleString) {
List<String> exampleList = null;
Map<String, String> exampleMap = getMap();
String exampleValue = exampleMap.get(exampleString);
// Does some stuff
exampleList = Arrays.asList(exampleValue.split(","));
return exampleList;
}
private Map<String, String> getMap(){
Map<String, String> exampleMap = new HashMap<>();
exampleMap.put("pre-defined String", "pre-defined String");
return exampleMap;
}
}
From what I can find- it seems like I want to use PowerMock, but I can't seem to figure it out.
A way to mock the return of the private method getMap() when it is called by the method getList.
You should be able to mock it using powermock
"Mocking of Private Methods Using PowerMock | Baeldung" https://www.baeldung.com/powermock-private-method
You will be able to return a call from private method provided its in the same class where the private method is

Using mockito. Trying to verify if my method was used

I use Mockito and JUnit 5. I have a small program that counts distinct characters in a string. I have a cache in the form of a Map and the result is picked from the cache if the input string had been processed before.
My goal is to write a test using Mockito to verify that the result is picked from the cache if the string had been processed before. I can't figure out how to use the verify Mockito method properly.
Here is my code:
public class CounterDecorator implements CharCounter{
Cache cache;
CharCounter counter;
public CounterDecorator(Cache cache, CharCounter counter) {
this.cache = cache;
this.counter=counter;
}
#Override
public Map<Character, Integer> count(String text) {
if(!cache.contains(text)) {
System.out.println("New entry in cache");
cache.putText(text, counter.count(text));
}
return cache.getText(text);
}
}
public class Cache {
private Map <String, Map<Character, Integer>> cache = new HashMap <>();
public void putText(String text, Map <Character, Integer> result) {
cache.put(text, result);
}
public Map<Character, Integer> getText(String text) {
return cache.get(text);
}
public boolean contains(String text) {
return cache.containsKey(text);
}
}
And tests:
#ExtendWith(MockitoExtension.class)
class DecoratorTest {
#Mock
Cache mcache;
#Mock
CharCounter mcharcounter;
#InjectMocks
CounterDecorator decorator;
#Test
void testWhenCacheIsNotEmpty() {
Map<Character, Integer> testMap = Collections.emptyMap();
verify(mcache, atLeastOnce()).putText("some string", testMap);
}
}
I am sure I use Mockito wrong. But I can't figure out how to resolve my problem. Thank you in advance.
EDIT. I edited my tests part a bit: removed that confusing map instantiation.

How to use Generic bounded param in method

I am trying to write some generic code and facing issue. Here is code
public abstract class AbstractService<D extends IDTO> {
public String ex(D dto) {
return null;
}
}
public class AService extends AbstractService<TestA> {
#Override
public String ex(TestA dto) {
return "a";
}
}
public class BService extends AbstractService<TestB> {
#Override
public String ex(TestB dto) {
return "b";
}
}
class TestA impements IDTO {
}
class TestB impements IDTO {
}
So as you can see, its really simple code, one AbstractService with bounded param that extends IDTO.
Two implementation of service AService and BService which uses their respective DTO.
Not there is another class that need to call ex() method on basis of runtime instance.
here I am facing the problem.
public class TestAll {
public void executeRequest(final IDTO dto){
// serviceMap contains list of all Services here A and B
serviceMap.get(type).ex(dto);
}
}
Problem on line build().
The method build(capture#5-of ? extends IDTO) in the type AbstractService is not applicable for the arguments (IDTO)
Could someone help to fix this issue?
I found the reason why it was giving me the error. It was my mistake as I was trying to build a map with the help of Spring and was using bounded approach.
It was my previous code.
#Autowired
public void setServicesList(List<AbstractService<IDTO>> abstractServices) {
serviceMap = abstractServices.stream().collect(Collectors.toMap(AbstractService::getType, Function.identity()));
}
and I had to remove the bounded approach and now it's working.
public void setServicesList(List<AbstractService> abstractServices) {
serviceMap = abstractServices.stream().collect(Collectors.toMap(AbstractService::getType, Function.identity()));
}
In case you know what type of service holds the Map, you could do following:
// define your service map
private final Map<String, AbstractService<? extends IDTO>> serviceMap = Map.of(
"a", new AService(),
"b", new BService());
// cast `AbstractServise` from the map into required type:
public void executeRequest(final TestA dto){
((AbstractService<TestA>)serviceMap.get("a")).ex(dto);
}
public void executeRequest(final TestB dto){
((AbstractService<TestB>)serviceMap.get("b")).ex(dto);
}

AssertionError when I try to write a unit test

I'm creating the processor to collect data and provide them in list. But when I'm trying to create test for my method i'm catching assertionerror. What am I doing wrong?
My Class:
#AllArgsConstructor
public class ZteProcessor implements OurProcessor {
private final static String VENDOR = "ZTE";
private String jsonString;
private Map<String, String> metricsGU;
private Map<String, String> metricsUMTS;
private Map<String, String> metricsLTE;
#Override
public List<TimingAdvance> getTA() throws ParseException, NotFoundPatternOrMetricsException {
TimeAdvanceDataStore data = new TimeAdvanceDataStore();
AllDataFromJSONFile fromJSONFile = ProcessorUtil.getAllData(jsonString);
if (jsonString.contains("String")) {
return data.allDataToTimingAdvance(VENDOR, fromJSONFile, metricsGU, 2);
} else if (jsonString.contains("String-2")) {
return data.allDataToTimingAdvance(VENDOR, fromJSONFile, metricsUMTS, 3);
} else if (jsonString.contains("String3")) {
return data.allDataToTimingAdvance(VENDOR, fromJSONFile, metricsLTE, 4);
} else {
throw new NotFoundPatternOrMetricsException();
}
}
}
My Test:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ProcessorUtil.class})
public class ZteProcessorTest {
#Mock
private AllDataFromJSONFile fromJSONFile;
#Mock
private TimeAdvanceDataStore data;
private OurProcessor processor;
private TimingAdvance timingAdvance = new TimingAdvance();
private Map<String, String> metricsGU = new HashMap<>();
private Map<String, String> metricsUMTS = new HashMap<>();
private Map<String, String> metricsLTE = new HashMap<>();
#Test
public void getTATest() throws Exception {
String jsonString = " { String : value}";
processor = new ZteProcessor(jsonString, metricsGU, metricsUMTS, metricsLTE);
List<TimingAdvance> list = new ArrayList<>();
list.add(timingAdvance);
PowerMockito.mockStatic(ProcessorUtil.class);
when(ProcessorUtil.getAllData(jsonString)).thenReturn(fromJSONFile);
when(data.allDataToTimingAdvance(jsonString, fromJSONFile, metricsGU, 2)).thenReturn(list);
assertEquals(list, processor.getTA());
}
}
Stacktrace:
java.lang.AssertionError:
Expected :[TimingAdvance{filial='null', vendor='null', cellName='null', periodDate=null, taMetrics=null}]
Actual :[]
<Click to see difference>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
My ZteProcessor using static method getAllData(jsonString) of class ProcessorUtill. And for it I use powermock.
The problem stems from the fact that you are setting your expectations on a TimeAdvanceDataStore data mock, but you are creating a new instance of TimeAdvanceDataStore in your method under test.
Since you are already using PowerMockito, you can tap into new object creation like
PowerMockito.whenNew(TimeAdvanceDataStore.class)
.withAnyArguments().thenReturn(data);
On top of that, think how many ZTEProcessors and TimeAdvanceDataStores you have in your app. Do you always want a new instance of TimeAdvanceDataStore in each call to getTA?
If not, just pass TimeAdvanceDataStore in a constructor.
If yes, common approaches when PowerMockito is not at your disposal are:
passing a factory of TimeAdvanceDataStore to ZTEProcessor constructor
passing TimeAdvanceDataStore to getTA method
extracting a method constructing TimeAdvanceDataStore and overriding it in test

Migrating from jMock1 custom invocation matchers to jMock2

I am using JMock-2.6.0. I have a map containing the names of methods and their expected return values.
I want to invoke a method on a mock object created using JMock.
Earlier I was able to this using JMock 1 as it follows following syntax:
mockObj.stubs().method(mymap.getKey()).will(new ReturnStub(mymap.getValue()));
But I am not sure, if there is a way to achieve this using JMock-2.
JMock-2's documentation is insufficient.
I believe this is the documentation you've been looking for:
Match Objects or Methods
Although matchers are normally used to specify acceptable parameter values, they can also be used to specify acceptable objects
or methods in an expectation, using an API syntax similar to that of
jMock 1. To do so, use a matcher where you would normally refer to a
mock object directly in the invocation count clause. Then chain
clauses together to define the expected invocation.
Their example includes:
To allow invocations of any bean property getter on any mock object:
allowing (any(Object.class)).method("get.*").withNoArguments();
For example you can use the following allowing... portion in a loop to achieve a similar result.
An sample test:
Interface:
public interface ThingOneI {
public abstract String getData();
public abstract void setData(String data);
public abstract String getRequest();
public abstract void setRequest(String request);
}
Impl:
public class ThingOne implements ThingOneI {
private String data;
private String request;
public ThingOne() {
}
#Override
public String getData() {
return data;
}
#Override
public void setData(String data) {
this.data = data;
}
#Override
public String getRequest() {
return request;
}
#Override
public void setRequest(String request) {
this.request = request;
}
}
Junit test:
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.junit.Before;
import org.junit.Test;
public class ThingOneTest {
Mockery context = new Mockery();
#Before
public void setUp() throws Exception {
}
#Test
public void test() {
ThingOneI thingOne = context.mock(ThingOneI.class);
Map<String, String> methMap = new HashMap<String, String>();
methMap.put("getData", "5");
context.checking(new Expectations() {{
for (Map.Entry<String, String> entry : methMap.entrySet())
allowing(any(ThingOneI.class))
.method(entry.getKey())
.with(any(String.class));
will(returnValue(entry.getValue()));
}
}});
System.out.println(thingOne.getData());
}
}

Categories

Resources