class Foo {
ReturnParameters function1(int a, int b) {
function2(a, b);
}
ReturnParameters function2(int a , int b) {
// body of this function...
}
}
I am creating a Junit test with Mockito and only want to test function1() and want to mock the returns from function2()
Below is my TestCase Class
class FooTest{
Foo foo = mock(Foo.class);
#Test
public void function1test(){
Mockito.when(foo.function2(1,2)).thenReturn(new ReturnParameters(100));
ReturnParameters actualResult = foo.function1(1,2);
int expectedResult = 100;
AssertEquals(expectedResult , actualResult.getStatus());
}
}
I am getting this error message that actualResult is a null value.
Can you please help?
You are attempting to partially stub the methods in a class.
In order to do this, you must use Spy instead of Mock.
Here is some sample code (that assumes you are using Junit5 and uses doReturn.when instead of when.thenReturn):
#ExtendWith(MockitoExtension.class)
class TestFoo
{
#Spy
private Foo spyClassToTest;
#BeforeEach
public void before()
{
// stub the function 2 call. The function 1 call is still "live"
doReturn(new ReturnParameters(100)).when(spyClassToTest).function2(1, 2);
}
#Test
public void function1_descriptionOfTheTestScenario_returns100()
{
ReturnParameters actualResult;
int expectedResult = 100;
// Perform the test
actualResult = spyClassToTest.function1(1, 2);
assertNotNull(actualResult);
assertEquals(expectedResult, actualResult.getStatus());
}
}
I don't know the domain but maybe its a good idea to split your functions into different classes. It should solve this issue in a clean way. Spy should also work though.
Related
MyCode:
class LocalClass{
public getNumber(){
retunr 5;
}
}
class AnotherLocalClass{
public static getNumber(){
retunr 10;
}
}
public class A{
public int methodAa(Boolean flag, int paramValue){
return methodA(flag, paramValue);
}
private int methodA(Boolean flag, int paramValue){
int returnValue = 0;
try{
if(flag){
LocalClass localVariable = new LocalClass();
returnValue = localVariable.getNumber() + paramValue;
} else{
returnValue = AnotherLocalClass.getNumber() + paramValue;
}
return returnValue;
}catch(Exception e){
e.printStackTrace();
return 0;
}
}
}
public class ATest{
#InjectMocks
A a;
public void methodATest(){
//need help to write here
}
}
LocalClass and AnotherLocalClass are classes that contains a method that returns a value.
getNumber in AnotherLocalClass is a static method.
Class A is the main class for which I am writing ATest class.
I can only write code in methodATest. And cannot change anything in LocalClass, AnotherLocalClass or class A.
I want to write methodATest such that methodA throws an exception.
My mockito version is 1.19.10 and it cannot be changed.
And also I cannot use PowerMockito or any other new dependency.
What exceptions do you expected to occur on your code? Which parameter values will cause the exceptions? In those cases, what is the return value that you're expecting?
When you get the answers for those questions, then you gonna have to set the conditions for the exception to happen. Then your code is gonna look something like this:
public class ATest{
A a = new A();
#Test
public void methodATest(){
Boolean flag = ?;
int paramValue = ?;
int expectedReturnValue = ?;
int returnValue = a.methodAa(flag, paramValue);
assertEquals(expectedReturnValue, returnValue);
}
}
Look out for the mock method. We usually use it when we need to set a class that we don't exactly want it to run it's methods, so we mock then to return something that we need for our test to work.
You can learn more about tests with this tutorial: https://www.vogella.com/tutorials/JUnit/article.html#junittesting
----[Edit]----
If you wanted to mock the LocalClass, you were gonna need to do something like this:
#PrepareForTest({LocalClass.class, A.class})
#RunWith(PowerMockRunner.class)
public class ATest{
A a = new A();
#Test
public void methodATest(){
PowerMockito.mockStatic(LocalClass.class);
PowerMockito.when(LocalClass.getNumber()).thenThrow(new Exception());
...
}
}
But, the getNumber() method should be static for it to work.
And, since you can not use PowerMockito, it's not possible to mock the class.
----[Edit]----
#PrepareForTest({AnotherLocalClass.class, A.class})
#RunWith(PowerMockRunner.class)
public class ATest{
A a = new A();
#Test
public void methodATest(){
PowerMockito.mockStatic(AnotherLocalClass.class);
PowerMockito.when(AnotherLocalClass.getNumber()).thenThrow(new Exception());
a.methodAa(...);
...
}
}
But again, since static method belongs to the class, there is no way in Mockito to mock static methods.
Class A
{
public B makeB(int q)
{
return new B(q);
}
public boolean evaluate(int q)
{
B b = makeB(q);
boolean result = b.get();
return result;
}
}
Class B
{
int e;
public B(int w)
{
e=w;
}
public boolean get()
{
//return boolean based on object B
}
}
Class ATest
{
A a = spy(A.class);
B b1 = mock(B.class);
B b2 = mock(B.class);
doReturn(b1).when(a).makeB(5);
doReturn(b2).when(a).makeB(10);
when(b1.get()).thenReturn(true);
when(b2.get()).thenReturn(false);
a.evaluate();
}
=======================
Here I would like to return true from method evaluate when object B contains value 5 and false if it contains value 10.
Class B is from an external Library.
New to unit testing and mockito.
The other answers are technically correct, but the first thing to understand: you should strive to not use a mocking framework like this.
Keep in mind: the purpose of a mocking framework is only to make testing possible/easier. Your mocking specs should be as simple as possible. Meaning: instead of thinking about having a mock giving different results on different parameters - the better solution is to have distinct tests and mocking specs, like:
#Test
public void testFooWithA() {
when(someMock.foo(eq(whateverA)).thenReturn(bar);
...
#Test
public void testFooWithB() {
when(someMock.foo(eq(whateverB)).thenReturn(somethingElse);
...
There are situations where you have write more sophisticated code to make your mocks "more smart". But most of the time when I had to do that - I stepped backed, and simplified my design under test. In other words: when your tests turn "too complicated" - most often the reason is a too complicated class/method under test.
You can achieve that using Mockito's Answer interface. It gives you access to call's actual arguments and you can differentiate returned value based on that.
Given interface
interface Measurer {
int measureLength(String s);
}
an example usage could look like
Measurer measurer = Mockito.mock(Measurer.class);
Mockito.when(measurer.measureLength(Mockito.any(String.class)))
.then((Answer<Integer>) invocationOnMock -> {
String arg = invocationOnMock.getArgumentAt(0, String.class);
if (arg.length() < 10) {
// mock Measurer can measure only short strings
return arg.length();
}
else {
return 42;
}
});
System.out.println(measurer.measureLength("abc")); // 3
System.out.println(measurer.measureLength("abcdefghijklmn")); // 42
In this case you could do:
doAnswer(new Answer<Boolean>() {
public Boolean answer(InvocationOnMock invocation) {
return invocation.getArgument(0) == 5;
}}).when(a.evaluate());
If you're asking how to get the actual value of 'b' inside the actual implementation of A#evaluate(), then you could add an answer for makeB for both mocks that set a local variable to the instance of B that is returned, so you know what it returned the last time it was called, then you could have your answer for evaluate() return based on the value of that local variable.
That is:
B lastB = null;
Answer<B> lastBAnswer = new Answer<B>() {
public B answer(InvocationOnMock invocation) {
if (invocation.<Integer>getArgument(0) == 5) {
lastB = b1;
} else {
lastB = b2;
}
return lastB;
}
};
doAnswer(lastBAnswer).when(a).makeB(any());
doAnswer(new Answer<Boolean>() {
public Boolean answer(InvocationOnMock invocation) {
return lastB.get();
}
}).when(a).evaluate();
I wouldn't recommend that path though, as it relies on temporal cohesion, but for testing it could be acceptable.
Note: Answering through StackOverflow without syntax checking this. Could be slightly off, but this is the rough idea.
I'm having problems with two void methods. In encouragedVenturesScoring I've followed this answer mocking an arraylist that will be looped in a for loop and haven't mocked the list, but passed a real list and added mocked objects.
Mockito gives me an InvalidUseOfMatchersException on this line
verify(effectList.get(Mockito.anyInt())).execute(playerHandler);
There are lots of questions on SO on this exception , and I think it's because of anyInt(). Anyway I changed it to
verify(effectList.get(0)).execute(playerHandler);
And now it's saying Wanted but not invoked effect.execute(playerHandler)
Actually there were zero interactions with this mock
Is it because I put doNothing ?
doNothing().when(effect).execute(playerHandler);
In my second method militaryStrengthScoring() method is there a way to skip the first chunk of code and just test the if..else condition? What would be the best approach to test this method?
Thank you for your time.
This is the class to be tested
public class EndGameScoringBaseController implements EndGameScoringHandler {
private static final int[] TERRITORIES_REWARD = {0,0,1,4,10,20};
private static final int[] CHARACTERS_REWARD = {1,3,6,10,15,21};
private static final int RESOURCES_RATE = 5;
private static final int FIRST_MILITARY_REWARD = 5;
private static final int SECOND_MILITARY_REWARD = 2;
private PlayerHandler player;
public EndGameScoringBaseController(PlayerHandler player) {
super();
this.player = player;
}
#Override
public void encouragedVenturesScoring() {
for (DevelopmentCard card : player.getPlayer().getPersonalBoard().getVentures()) {
for (Effect e : card.getPermanentEffects())
e.execute(player);
}
}
#Override
public void militaryStrengthScoring(GameController game) {
Set<Integer> points = new HashSet<>();
int myPoints = this.player.getPointsHandler().getMilitaryPoints();
for (PlayerHandler p: game.getPlayers()) {
points.add(p.getPointsHandler().getMilitaryPoints());
}
int[] rank = new int[points.size()];
int j = 0;
for (Integer i : points) {
rank[j] = i;
j++;
}
Arrays.sort(rank);
if (rank[rank.length-1] == myPoints) {
player.getPointsHandler().winMilitaryPoints(FIRST_MILITARY_REWARD);
}
else if (rank[rank.length-2] == myPoints) {
player.getPointsHandler().winVictoryPoints(SECOND_MILITARY_REWARD);
}
}
Tested method for encouragedVenturesScoring
#Test
public void encouragedVenturesScoringTest() {
//given
List<DevelopmentCard> ventureList;
ventureList = Arrays.asList(developmentCard, developmentCard);
when(playerHandler.getPlayer().getPersonalBoard().getVentures()).thenReturn(ventureList);
List<Effect> effectList;
effectList = Arrays.asList(effect, effect);
when(developmentCard.getPermanentEffects()).thenReturn(effectList);
doNothing().when(effect).execute(playerHandler);
//when
endgameController.encouragedVenturesScoring();
//then
verify(effectList.get(Mockito.anyInt())).execute(playerHandler);
}
Incomplete tested method for militaryStrengthScoring
#Test
public void militaryStrengthScoringTest() {
//given
when(playerHandler.getPointsHandler().getMilitaryPoints()).thenReturn(4);
doNothing().when(playerHandler.getPointsHandler()).winMilitaryPoints(FIRST_MILITARY_REWARD);
//when
endgameController.militaryStrengthScoring(gameController);
//then
/../
}
You're right that this is the problem:
verify(effectList.get(Mockito.anyInt())).execute(playerHandler);
Mockito only allows for calls like any() and anyInt() to stand in for parameters to the mock themselves, due to the internal implementation of matchers.
/* OK */ when(yourMock.yourMethod(anyInt())).thenReturn(42);
/* BAD */ when(yourList.get(anyInt()).yourMethod(0)).thenReturn(42);
/* OK */ verify(yourMock).yourMethod(anyInt());
/* BAD */ verify(yourList.get(anyInt())).yourMethod(0);
The failure with get(0) is likely an actual failure, and may be related to the fact that your encouragedVenturesScoringTest is actually not calling encouragedVenturesScoring, it's calling influencedCharactersScoring. If this continues to give you trouble after fixing that error, in ways related to Mockito, please edit your question.
You can only verify mock objects created by Mockito.
But effectList is a "real" list. Therefore Mockito knows nothing about that object. Thus any attempt to verify that list must fail.
If you want to verify that object - then you have to mock it!
Of course, this means that you have specify all calls that will go to the mocked list.
I'm using Mockito to mock a method to return a Date when given a Date.
when(supplier.calculateDeliveryDate(any(Date.class)))
.thenReturn(supplierDeliveryDate);
However, I only want it to return the supplierDeliveryDate when it is passed a non-null Date object.
When passed null, it should return null.
Is this possible? How can I do it?
Use ArgumentMatchers.isNull() matcher.
when(supplier.calculateDeliveryDate(any(Date.class)))
.thenReturn(supplierDeliveryDate);
when(supplier.calculateDeliveryDate(isNull()))
.thenReturn(null);
You could use an anonymous inner class:
// unit test
public OrderServiceTest {
// instance of class-under-test
private OrderService instance;
// stub value
private Date supplierDeliveryDate = new Date();
// mock as an anonymous inner class
private Supplier supplier = new Supplier() {
public Date calculateDeliveryDate(Date input) {
if (input == null) {
return null;
}
else {
return supplierDeliveryDate;
}
}
};
#Before
public void setUp() {
instance = new OrderService();
// dependency injection
instance.setSupplier(supplier);
}
#Test
public void testOrderHappy() {
// SETUP
Date orderDate = new Date();
// CALL
Date result = instance.order(orderDate);
// VERIFY
assertTrue(supplierDeliveryDate == result);
}
#Test
public void testOrderNull() {
// SETUP
Date orderDate = null;
// CALL
Date result = instance.order(orderDate);
// VERIFY
assertNull(result);
}
}
But you should really wonder why you need this kind of behavior.
If you write a well defined test case then you should know exactly how often, and with which arguments, your mock is called. If so, then you can just stub the expected calls instead of wiring your mock with conditional behavior.
Note that is is useful if your test is as 'sharp' as possible. If a different number of calls hits your mock than expected, or with different arguments, then the test should fail.
You can use helper method:
public static <T> void validateAndMock(Supplier<T> ongoingStubbing, T mockedResponse) {
if (mockedResponse != null) {
when(ongoingStubbing.get()).thenReturn(mockedResponse);
}
}
And then call:
validateAndMock(() -> supplier.calculateDeliveryDate(any(Date.class)), supplierDeliveryDate);
My first method is simple, its just a toString which outputs 3 class specific fields
public String toString(){
return String.format("%s/%s/%s",street,city,postcode);
}
In JUnit it gives me this to form the tests on, I am unsure how to do this efficiently.
#Test
public void testToString() {
System.out.println("toString");
Address instance = null;
String expResult = "";
String result = instance.toString();
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
I have done lots of research on JUnit and understand the concept of testing but can't quite get my head around how to do it with my code. Also how would I test this method efficiently, this is a method in a subclass which is the abstract method in the parent class
#Override
int getDiscountRate() {
return this.companyDiscount;
}
It gives me this to test
#Test
public void testGetDiscountRate() {
System.out.println("getDiscountRate");
BusinessOrganisationDetails instance = null;
int expResult = 0;
int result = instance.getDiscountRate();
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
This looks good. Of course, you need to instanciate the instance variables, else it will result in a NullPointerException.
Here, how it could look like in the end:
#Test
public void testToString() {
System.out.println("toString");
Address instance = new Address();
instance.setStreet("Somestreet");
instance.setCity("Somecity");
instance.setPostcode("12345");
String expResult = "SomestreetSomecity12345";
String result = instance.toString();
assertEquals(expResult, result);
}
And the other test:
#Test
public void testGetDiscountRate() {
System.out.println("getDiscountRate");
BusinessOrganisationDetails instance = new BusinessOrganisationDetails();
instance.setCompanyDiscount(50);
int expResult = 50;
int result = instance.getDiscountRate();
assertEquals(expResult, result);
}