Mockito mock object using real implementation - java

Why is mockMap using the real implementation?
How do I prevent this?
In method testFirstKeyMatch
when(mockMap.keySet().toArray()[0])...
throws ArrayIndexOutOfBoundsException: 0 when running the test.
MaxSizeHashMap is a LinkedHashMap with max size of 7,
throws an IndexOutOfBoundsException when I attempt to put more into.
Profile keeps track of something not essential for this.
SuperClass.java
public class SuperClass {
protected String[] days;
protected MaxSizeHashMap<String, String> map;
public SuperClass() {
days = new String[7];
map = new MaxSizeHashMap<String, String>();
//...
}
void updateDays() {
cal = Calendar.getInstance();
for (int i = 0; i < 7; i = i + 1) {
//adds short names "Mon", "Tue", ... to days
days[i] = cal.getDisplayName(Calendar.DAY_OF_WEEK,
Calendar.SHORT, Locale.US);
cal.add(Calendar.DATE, 1);
}
}
void firstKeyMatch(Profile profile) {
updateDays();
//checks if first key of map is not same as days[0]
if (days[0] != map.keySet().toArray()[0]) {
profile.add();
//...
}
}
}
SuperClassTest.java
#RunWith(MockitoJUnitRunner.class)
public class SuperClassTest {
#InjectMocks
private SuperClass spr = new SuperClass();
#Mock
private MaxSizeHashMap<String, String> mockMap;
#Mock
private Profile mockProfile;
//...
#Test
public void testFirstKeyMatch() {
when(mockMap.keySet().toArray()[0]).thenReturn(spr.days[0]);
verify(mockProfile, never()).add();
}
}

As per the documentation, mockito's implicit behaviour for a mock is to return default values.
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. For example 0 for an int/Integer and false for a boolean/Boolean.
In consequence, your mockMap.keySet() will return an empty hash-set, which you then convert to an empty array and try to retrieve the (non-existent) first element, hence the IOOBE.
In conclusion, mockito is not using the real implementation, but it's behaving normally as it's supposed to.
You did not post the entire constructor of SuperClass, but probably after you instantiate the map, you also populate it with values. If that's true, then one can argue that the exception is actually proof that mockito does not use the real implementation, because you'd really be getting the first element.
As for the solutions, well it's already been suggested to return your own hash set with whatever data you require (credits go to Abubakkar):
when(mockMap.keySet()).thenReturn(new HashSet(Arrays.asList("your day string")));

To redirect all mockMap.keySet().toArray()[i] calls to spr.days[i], you can tell mockMap to return the days array when someone requests the key set.
Set keySetMock = mock(Set.class);
when(keySetMock.toArray()).thenReturn(spr.days);
when(mockMap.keySet()).thenReturn(keySetMock);

Related

How to mock according to the number of invocations of method using java and Mockito? [duplicate]

Is there a way to have a stubbed method return different objects on subsequent invocations? I'd like to do this to test nondeterminate responses from an ExecutorCompletionService. i.e. to test that irrespective of the return order of the methods, the outcome remains constant.
The code I'm looking to test looks something like this.
// Create an completion service so we can group these tasks together
ExecutorCompletionService<T> completionService =
new ExecutorCompletionService<T>(service);
// Add all these tasks to the completion service
for (Callable<T> t : ts)
completionService.submit(request);
// As an when each call finished, add it to the response set.
for (int i = 0; i < calls.size(); i ++) {
try {
T t = completionService.take().get();
// do some stuff that I want to test
} catch (...) { }
}
How about
when( method-call ).thenReturn( value1, value2, value3 );
You can put as many arguments as you like in the brackets of thenReturn, provided they're all the correct type. The first value will be returned the first time the method is called, then the second answer, and so on. The last value will be returned repeatedly once all the other values are used up.
You can do that using the thenAnswer method (when chaining with when):
when(someMock.someMethod()).thenAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
});
Or using the equivalent, static doAnswer method:
doAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
}).when(someMock).someMethod();
As previously pointed out almost all of the calls are chainable.
So you could call
when(mock.method()).thenReturn(foo).thenReturn(bar).thenThrow(new Exception("test"));
//OR if you're mocking a void method and/or using spy instead of mock
doReturn(foo).doReturn(bar).doThrow(new Exception("Test").when(mock).method();
More info in Mockito's Documenation.
Almost all of the calls are chainable:
doReturn(null).doReturn(anotherInstance).when(mock).method();
BDD style:
import static org.mockito.BDDMockito.given;
...
given(yourMock.yourMethod()).willReturn(1, 2, 3);
Classic style:
import static org.mockito.Mockito.when;
...
when(yourMock.yourMethod()).thenReturn(1, 2, 3);
Explicit style:
...
when(yourMock.yourMethod())
.thenReturn(1)
.thenReturn(2)
.thenReturn(3);
Depending on an arg
Suppose we have 2 args, and check the size of the 2nd (list) arg:
...
when(yourMock.yourMethod(any(), anyList()))
.thenAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
args are Objects, so we have to cast an arg to our type. I cast ^^^ to (List) in my case.
BDD
...
given(yourMock.yourMethod(any(), anyList()))
.willAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
I've implemented a MultipleAnswer class that helps me to stub different answers in every call. Here the piece of code:
private final class MultipleAnswer<T> implements Answer<T> {
private final ArrayList<Answer<T>> mAnswers;
MultipleAnswer(Answer<T>... answer) {
mAnswers = new ArrayList<>();
mAnswers.addAll(Arrays.asList(answer));
}
#Override
public T answer(InvocationOnMock invocation) throws Throwable {
return mAnswers.remove(0).answer(invocation);
}
}
doReturn( value1, value2, value3 ).when( method-call )
Related to #[Igor Nikolaev]'s answer from 8 years ago, using an Answer can be simplified somewhat using a lambda expression available in Java 8.
when(someMock.someMethod()).thenAnswer(invocation -> {
doStuff();
return;
});
or more simply:
when(someMock.someMethod()).thenAnswer(invocation -> doStuff());
If you have a dynamic list of values you can use AdditionalAnswers.returnsElementsOf:
import org.mockito.AdditionalAnswers;
when(mock.method()).thenAnswer(AdditionalAnswers.returnsElementsOf(myListOfValues));
Following can be used as a common method to return different arguments on different method calls. Only thing we need to do is we need to pass an array with order in which objects should be retrieved in each call.
#SafeVarargs
public static <Mock> Answer<Mock> getAnswerForSubsequentCalls(final Mock... mockArr) {
return new Answer<Mock>() {
private int count=0, size=mockArr.length;
public Mock answer(InvocationOnMock invocation) throws throwable {
Mock mock = null;
for(; count<size && mock==null; count++){
mock = mockArr[count];
}
return mock;
}
}
}
Ex. getAnswerForSubsequentCalls(mock1, mock3, mock2); will return mock1 object on first call, mock3 object on second call and mock2 object on third call.
Should be used like when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2));
This is almost similar to when(something()).thenReturn(mock1, mock3, mock2);
You can use a LinkedList and an Answer. Eg
MyService mock = mock(MyService.class);
LinkedList<String> results = new LinkedList<>(List.of("A", "B", "C"));
when(mock.doSomething(any())).thenAnswer(invocation -> results.removeFirst());
This is not directly related to the question. But wanted to put this in the same chain.
If trying to verify the same method call with multiple arguments, you can use the below times feature by Mockito. You don't need it if you are not verifying.
Mockito.verify(method, times(n)).methoscall();
Here is 'n' is the number of times the mock is invoked.
This might be basic/obvious, but if like me you are trying to mock multiple calls for a method that is called unknown number of times per call to method to be tested, for example:
public String method(String testArg) {
//...
while(condition) {
someValue = someBean.nestedMethod(); // This is called unknown number of times
//...
}
//...
}
You can do something like:
#Test
public void testMethod() {
mockNestedMethodForValue("value1");
assertEquals(method("arg"), "expected1");
mockNestedMethodForValue("value2");
assertEquals(method("arg"), "expected2");
mockNestedMethodForValue("value3");
assertEquals(method("arg"), "expected3");
}
private void mockNestedMethodForValue(String value) {
doReturn(value).when(someBeanMock).nestedMethod();
}
Here is working example in BDD style which is pretty simple and clear
given(carRepository.findByName(any(String.class))).willReturn(Optional.empty()).willReturn(Optional.of(MockData.createCarEntity()));

Refactoring Java8 code with Functional Interface

Input:
public BigDecimal getMaxValuation(ServiceData data) {
System.out.println("getMaxValuation()");
BigDecimal calculatedAmount;
//4 String returnValue = getReturnValue(data);
Function<ServiceData,String> returnValueFn = this::getReturnValue;
BigDecimal orderSize = getOrderSize(returnValueFn.apply(data),60);
Predicate<String> gasPredicate = "GAS"::equalsIgnoreCase;
Predicate<String> oilPredicate = "OIL"::equalsIgnoreCase;
if(gasPredicate.test(returnValueFn.apply(data)))
calculatedAmount = callA(data.getValuation())
else if(oilPredicate.test(returnValueFn.apply(data)))
calculatedAmount = callB(data.getValuation())
else
calculatedAmount = callC(data.getValuation())
return calculatedAmount;
}
public String getReturnValue(ServiceData data){
System.out.println("getReturnValue()");
return returnValue;
}
In the above function getMaxValuation(), when we comment line#4 and replace it with a Function<ServiceData,String>,
getReturnValue() is getting called 3 times during the execution. But when we uncomment the line #4 and remove all the
Function<ServiceData,String> related change the getReturnValue() is getting called only once.
When we use Function is there any way to achieve the same behavior ?
Whether you invoke a method directly or using a functional interface, the logic of invoking it once and storing the result in a local variable to avoid repeated evaluation doesn’t change.
So far, your rewriting of the direct invocations into uses of a functional interface looks like an end in itself, without actually improving anything but only making the code more complicated.
One way of using functional programming to improve your code would be using a map of functions to replace the if-else ladder by a single lookup:
static final Map<String, Function<Valuation,BigDecimal>> METHOD;
static {
Map<String, Function<Valuation,BigDecimal>> m
= new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
m.put("GAS", ContainingClass::callA);
m.put("OIL", ContainingClass::callB);
METHOD = Collections.unmodifiableMap(m);
}
public BigDecimal getMaxValuation(ServiceData data) {
// don't know how to incorporate this, as it was entirely unused
// BigDecimal orderSize = getOrderSize(getReturnValue(data), 60);
return METHOD.getOrDefault(getReturnValue(data), ContainingClass::callC)
.apply(data.getValuation());
}
Where Valuation refers to the return type of ServiceData.getValuation() and ContainingClass is the declaring class of callA, callB, and callC, assuming static methods.
If these methods are non-static, the code would have to look like
static final Map<String, BiFunction<ContainingClass,Valuation,BigDecimal>> METHOD;
static {
Map<String, BiFunction<ContainingClass,Valuation,BigDecimal>> m
= new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
m.put("GAS", ContainingClass::callA);
m.put("OIL", ContainingClass::callB);
METHOD = Collections.unmodifiableMap(m);
}
public BigDecimal getMaxValuation(ServiceData data) {
return METHOD.getOrDefault(getReturnValue(data), ContainingClass::callC)
.apply(this, data.getValuation());
}

Updating original values after passing them as params to a new method instead of references

I have a method whose some parts of are repetitive. I managed to split the code in a way that the original method uses smaller methods many times. The problem is that when I pass some values as params to those new smaller methods and work with them, original values don't get updated. The actions I do are: value incrementation or removing items from arraylist. How do I update the original values using the smaller methods, not only the references? The only possible solution I came up with is to create a new class where I could have a setter for those values and update them. But are there easier/straightforward ways to solve it?
Part of the main method:
int numberOfBlocks = 0;
int currentBlock = 0;
int currentTime = 0;
ArrayList<Request> queue = new ArrayList<Request>();
if(queue.size != 0) {
updateStatus(queue, currentBlock, numberOfBlocks);
}
if(something else happens) {
removeFinished(queue, currentBlock);
}
Smaller methods:
private void updateStatus(ArrayList<Request> queue, int currentBlock, int numberOfBlocks) {
if (queue.get(0).getBlock() > currentBlock)
currentBlock++;
else
currentBlock--;
numberOfBlocks++;
}
private void removeFinished(ArrayList<Request> queue, int currentBlock){
if (queue.get(0).getBlock() == currentBlock) {
queue.remove(0);
}
}
First of all, if you pass a parameter in order for it to be changed in the method, your method should return the changed value, this will resolve your issue. If more then one value needs to be changed, then you are correct, primitives are passed y value and the invoking method doesn't see the changes made in the invoked method. So you should encapsulate those values in a wrapping class with setters and getters like you wanted to. That alone will resolve your problem. But also it would make sense for your method to return that class since it is modified. This is just a good stile
If the smaller methods are in the same class as the main method, simply don't pass them as parameters and the methods will use the class's fields. This is non-thread safe, but your class is non-thread safe already anyway.
class MyClass
{
int numberOfBlocks = 0;
int currentBlock = 0;
int currentTime = 0;
ArrayList<Request> queue = new ArrayList<Request>();
void myMainMethod() {
if(queue.size != 0) {
updateStatus();
}
if(something else happens) {
removeFinished();
}
}
private void updateStatus() {
if (queue.get(0).getBlock() > currentBlock)
currentBlock++;
else
currentBlock--;
numberOfBlocks++;
}
private void removeFinished() {
if (queue.get(0).getBlock() == currentBlock) {
queue.remove(0);
}
}

assertEquals() with HashSet

I have a constructor for the class of player
public Player(String name, String playerDescription,
HashSet<String> abilities) {
this.name = name;
this.playerDescription;
this.abilities = abilities;
}
I create an instance of this class
Player p = new Player ("Jon Snow", "Brave Swordsman", new HashSet<String>());
I've created an addAbilities() method, to add to the HashSet.
public void addAbilities(String newAbility) {
abilities.add(newAbility);
}
However, when I go to test the method (using a get method)
public String getAbility() {
String abilityString = abilities.toString();
return abilityString;
}
My test :
#Test
public void testAddAbility() {
Player p = new Player("Jon Snow", "Brave Swordsman", new HashSet<String>());
s.addAbility("Leadership");
assertEquals("Leadership", s.getAbility());
}
I get an difference in the test output.
Comparison failure: expected: <[Leadership]> but was <[[Leadership]]>
My question is, why is there a difference in output and is it good practice to make a HashSet this way?
HashSet.toString() returns a String displaying the elements inside [] (and with , character between them).
So in your assertion you compare Leadership to [Leadership].
This would be ok for the assertion :
assertEquals("[Leadership]", s.getAbility());
But I think that you should rather change the method to retrieve abilities.
Is it a retrieval and formatting method ?
Rename the method in this sense.
Otherwise, keep the Set abstraction and just return the Set as it is :
public Set<String> getAbilities(){
return abilities;
}
The format for a Set toString output is "[item1, item2, ...]". You only have one item, so it's "[item1]".
I'd suggest you make this method
public Set<String> getAbilities()
Or better yet
public Set<Ability> getAbilities()
your code has potentially flaws at a couple of points, the first one is
ability is a collection, so this getter is not correct because it returns a String
public String getAbility() {
String abilityString = abilities.toString();
return abilityString;
}
so that "getter" is giving back a string that java JDK developers can change without even inform anybody... as a concecuense of that
the #test is failing....
you should return a (an unmodifiable) collection in the getter and from that check whether the string value is present...
Set<String> mySet = new HashSet<>();
mySet.add("Leader");
mySet.contains("Leader");
now you are indeendent of what is happening in the future with the toString implementation of the hashSet
I suggest removing the getAbility() method and adding:
public boolean hasAbility(String ability) {
return abilities.contains(ability);
}
as for testing the addition method, you can do this:
#Test
public void testAddAbility() {
Player p = new Player("Jon Snow", "Brave Swordsman", new HashSet<String>());
p.addAbility("Leadership");
assertTrue(p.hasAbility("Leadership"));
}

Using Mockito with multiple calls to the same method with the same arguments

Is there a way to have a stubbed method return different objects on subsequent invocations? I'd like to do this to test nondeterminate responses from an ExecutorCompletionService. i.e. to test that irrespective of the return order of the methods, the outcome remains constant.
The code I'm looking to test looks something like this.
// Create an completion service so we can group these tasks together
ExecutorCompletionService<T> completionService =
new ExecutorCompletionService<T>(service);
// Add all these tasks to the completion service
for (Callable<T> t : ts)
completionService.submit(request);
// As an when each call finished, add it to the response set.
for (int i = 0; i < calls.size(); i ++) {
try {
T t = completionService.take().get();
// do some stuff that I want to test
} catch (...) { }
}
How about
when( method-call ).thenReturn( value1, value2, value3 );
You can put as many arguments as you like in the brackets of thenReturn, provided they're all the correct type. The first value will be returned the first time the method is called, then the second answer, and so on. The last value will be returned repeatedly once all the other values are used up.
You can do that using the thenAnswer method (when chaining with when):
when(someMock.someMethod()).thenAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
});
Or using the equivalent, static doAnswer method:
doAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
}).when(someMock).someMethod();
As previously pointed out almost all of the calls are chainable.
So you could call
when(mock.method()).thenReturn(foo).thenReturn(bar).thenThrow(new Exception("test"));
//OR if you're mocking a void method and/or using spy instead of mock
doReturn(foo).doReturn(bar).doThrow(new Exception("Test").when(mock).method();
More info in Mockito's Documenation.
Almost all of the calls are chainable:
doReturn(null).doReturn(anotherInstance).when(mock).method();
BDD style:
import static org.mockito.BDDMockito.given;
...
given(yourMock.yourMethod()).willReturn(1, 2, 3);
Classic style:
import static org.mockito.Mockito.when;
...
when(yourMock.yourMethod()).thenReturn(1, 2, 3);
Explicit style:
...
when(yourMock.yourMethod())
.thenReturn(1)
.thenReturn(2)
.thenReturn(3);
Depending on an arg
Suppose we have 2 args, and check the size of the 2nd (list) arg:
...
when(yourMock.yourMethod(any(), anyList()))
.thenAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
args are Objects, so we have to cast an arg to our type. I cast ^^^ to (List) in my case.
BDD
...
given(yourMock.yourMethod(any(), anyList()))
.willAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
I've implemented a MultipleAnswer class that helps me to stub different answers in every call. Here the piece of code:
private final class MultipleAnswer<T> implements Answer<T> {
private final ArrayList<Answer<T>> mAnswers;
MultipleAnswer(Answer<T>... answer) {
mAnswers = new ArrayList<>();
mAnswers.addAll(Arrays.asList(answer));
}
#Override
public T answer(InvocationOnMock invocation) throws Throwable {
return mAnswers.remove(0).answer(invocation);
}
}
doReturn( value1, value2, value3 ).when( method-call )
Related to #[Igor Nikolaev]'s answer from 8 years ago, using an Answer can be simplified somewhat using a lambda expression available in Java 8.
when(someMock.someMethod()).thenAnswer(invocation -> {
doStuff();
return;
});
or more simply:
when(someMock.someMethod()).thenAnswer(invocation -> doStuff());
If you have a dynamic list of values you can use AdditionalAnswers.returnsElementsOf:
import org.mockito.AdditionalAnswers;
when(mock.method()).thenAnswer(AdditionalAnswers.returnsElementsOf(myListOfValues));
Following can be used as a common method to return different arguments on different method calls. Only thing we need to do is we need to pass an array with order in which objects should be retrieved in each call.
#SafeVarargs
public static <Mock> Answer<Mock> getAnswerForSubsequentCalls(final Mock... mockArr) {
return new Answer<Mock>() {
private int count=0, size=mockArr.length;
public Mock answer(InvocationOnMock invocation) throws throwable {
Mock mock = null;
for(; count<size && mock==null; count++){
mock = mockArr[count];
}
return mock;
}
}
}
Ex. getAnswerForSubsequentCalls(mock1, mock3, mock2); will return mock1 object on first call, mock3 object on second call and mock2 object on third call.
Should be used like when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2));
This is almost similar to when(something()).thenReturn(mock1, mock3, mock2);
You can use a LinkedList and an Answer. Eg
MyService mock = mock(MyService.class);
LinkedList<String> results = new LinkedList<>(List.of("A", "B", "C"));
when(mock.doSomething(any())).thenAnswer(invocation -> results.removeFirst());
This is not directly related to the question. But wanted to put this in the same chain.
If trying to verify the same method call with multiple arguments, you can use the below times feature by Mockito. You don't need it if you are not verifying.
Mockito.verify(method, times(n)).methoscall();
Here is 'n' is the number of times the mock is invoked.
This might be basic/obvious, but if like me you are trying to mock multiple calls for a method that is called unknown number of times per call to method to be tested, for example:
public String method(String testArg) {
//...
while(condition) {
someValue = someBean.nestedMethod(); // This is called unknown number of times
//...
}
//...
}
You can do something like:
#Test
public void testMethod() {
mockNestedMethodForValue("value1");
assertEquals(method("arg"), "expected1");
mockNestedMethodForValue("value2");
assertEquals(method("arg"), "expected2");
mockNestedMethodForValue("value3");
assertEquals(method("arg"), "expected3");
}
private void mockNestedMethodForValue(String value) {
doReturn(value).when(someBeanMock).nestedMethod();
}
Here is working example in BDD style which is pretty simple and clear
given(carRepository.findByName(any(String.class))).willReturn(Optional.empty()).willReturn(Optional.of(MockData.createCarEntity()));

Categories

Resources