Reputation: 3191
I don't understand why test1()
fails although it does the same as test2()
. And the other test method succeeds...
I get NPE in assertTrue(str.equals("hello"));
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import junit.framework.TestCase;
class UnderTest {
private static UnderTest instance;
private ToMock toMock;
public void doSomething() {
String str = toMock.get();
assertTrue(str.equals("hello"));
}
public static UnderTest getInstance() {
if (instance == null) {
instance = new UnderTest();
}
return instance;
}
public void set(ToMock toMock) {
this.toMock = toMock;
}
public ToMock get() {
return toMock;
}
}
public class SomeTest extends TestCase {
private ToMock toMock;
private UnderTest underTest;
private String str;
public SomeTest() {
toMock = mock(ToMock.class);
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
str = (String) args[0];
return null;
}
}).when(toMock).set((String) org.mockito.Mockito.any());
when(toMock.get()).thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
return str;
}
});
UnderTest.getInstance().set(toMock);
}
@Before
public void setUp() throws Exception {
// UnderTest.getInstance().set(toMock);
}
@After
public void tearDown() throws Exception {
}
@Test
public void test1() {
toMock.set("hello");
UnderTest.getInstance().doSomething();
}
@Test
public void test2() {
toMock.set("hello");
UnderTest.getInstance().doSomething();
}
}
The interface below should be placed in an extra file. Otherwise it can't be mocked by Mockito.
public interface ToMock {
void set(String str);
String get();
}
But as soon as I uncomment:
@Before
public void setUp() throws Exception {
// UnderTest.getInstance().set(toMock);
}
both methods will succeed. I don't see how this instruction affects the str
field. It looks like str
is set to null
between the invocations of test1()
and test2()
. But why and where? As far as I know I don't have to call setUp()
just to keep the current values of some fields. The state of SomeTest
(str
included) shouldn't be lost between the test method invocations in JUnit.
How can it be explained?
Upvotes: 4
Views: 821
Reputation: 279990
You're mixing JUnit 3 and JUnit 4. Don't. Get rid of the
extends TestCase {
which presumably makes your test runner use JUnit 3 for running the tests.
JUnit always create a new instance of the test class to run each test method.
In JUnit 3, the runner prepares all instances before executing any of the methods. In your case, execution basically goes like this
SomeTest
, instance AToMock
, instance B, bound to instance A, and register it in UnderTest
singletonSomeTest
, instance CToMock
, instance D, bound to instance C, and register it in UnderTest
singleton, overwriting what was there beforetest1
on instance Aset
on ToMock
instance BdoSomething
on ToMock
instance D because that's the one stored in UnderTest
singleton, retrieved through getInstance
That ToMock
instance D hasn't had set
called on it yet. The corresponding SomeTest
instance C
's str
field is therefore still null
.
With JUnit 4, we alternate creating an instance with running the corresponding test. In your test case, the UnderTest
singleton wouldn't be "poluted" with the wrong ToMock
instance.
Upvotes: 5
Reputation: 915
Any updates to setup method (@Before) and @After annotated methods will persist between method calls.
@Before
public void executedBeforeEach() {
....
}
The call however will be invoked each time before/after test method is called. If this is not sufficient for you then consider using @BeforeClass annotations.
Upvotes: 1