mardi 16 août 2016

Mock state is lost between JUnit test method invocations

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?

Aucun commentaire:

Enregistrer un commentaire