Reputation: 679
I have a TestClass
and I am writing unit test cases for calculate()
method of TestClass
. Please refer to the code below.
public class TestClass {
public int calculate() {
System.out.println("calculating area");
String shape = getShape(1);
int radius = 10;
int result = findArea(shape, radius);
return result;
}
public String getShape(int index) {
if(index == 1) {
return "circle";
}
else {
return "square";
}
}
public int findArea(String shape, int radius) {
if(shape == "circle") {
return 3 * radius * radius;
}
else {
return radius * radius;
}
}
}
While mocking getShape() function, I want the mock to return "square" when I pass the value 1. Please refer to the unit test below.
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
public class TestClassTest {
//TestClass testClass;
@Before
public void init() {
TestClass testClass = new TestClass();
System.out.println("Inside before");
}
@Test
public void calculateTest() {
int expected = 100;
TestClass testClass = new TestClass();
TestClass testClassMock = Mockito.mock(TestClass.class);
Mockito.when(testClassMock.getShape(1)).thenReturn("square");
int actual = testClass.calculate();
assertEquals(expected, actual);
}
}
The test is failing with error, expected 100, but was 300. So it's clear that the getShape(1)
returns value circle, instead of the value I provided using Mockito.when()
. Please let me know what mistake I'm making.
Upvotes: 3
Views: 8852
Reputation: 11
Mocking only when using the object as spring instance is the primary requirement for mocking and that has been discussed often.
its also important to understand the sequence of mockito.doReturn() and mockito.init(). Make sure mockito.init is called first.
you can achieve that through annotation to make sure init() is always first. -AB
Upvotes: 1
Reputation: 12235
As also the other answer suggests you can use a spy. I would rather initialize it with @Spy
annotation and get totally rid of your @Before
method, so like:
@Spy
private TestClass testClass;
@Test
public void calculateTest() {
int expected = 100;
Mockito.when(testClass.getShape(1)).thenReturn("square");
int actual = testClass.calculate();
assertEquals(expected, actual);
}
// This just to show that if you do not spy any methods it works as "normal" TestClass
@Test
public void calculateTestNotSpied() {
int expected = 300;
int actual = testClass.calculate();
assertEquals(expected, actual);
}
Also - I am not sure if it is a big problem - but you seem to mix Junit4 & Junit5 (Jupiter) annotations and assertions. It might be a good idea to use only one of them (4|5) in your tests.
Upvotes: 2
Reputation: 3812
Problem is when you have created two separate instances of class TestClass
and then calling the method calculate
with one instance of class TestClass testClass
and you have Mocked and assigned the return values in the separate instance testClassMock
, so the mocked values do not play any roles while you are running the test cases.
TestClass testClass = new TestClass();
TestClass testClassMock = Mockito.mock(TestClass.class);
The simple solution is that you should have single instances for calling the test method and mock method, for more details, visit the below questions:
and for you solution, below is the code:
TestClass testClass = Mockito.spy(new TestClass());
Mockito.doReturn("square").when(testClass).getShape(ArgumentMatchers.anyInt());
int actual = testClass.calculate();
Upvotes: 0
Reputation: 311853
You're mocking an object, but then you never use this mock. It looks like you meant to spy (i.e., partially mock) the object under test in such a way that getShape
is mocked away, but calculate
's real implementation is called:
@Test
public void calculateTest() {
int expected = 100;
TestClass testClass = Mockito.spy(new TestClass());
Mockito.doReturn("square").when(testClass).getShape(1);
int actual = testClass.calculate();
assertEquals(expected, actual);
}
Upvotes: 3