Kategorien
Java

EasyMock, Unitils and a mixture of both

So, we do use unitils and easymock for quite a while now. We do our mocking with easymock and use the unitils-inject and unitils-easymock modules to simplify our tests.

But, there was a very weird behaviour. So I tried to boil it down to the reason why it fails. Here is some code that we actually want to test:

package de.matthiascoy.easymock.easymockprimitivetest;
public interface InterfaceB {
    void foobar(boolean b);
}
package de.matthiascoy.easymock.easymockprimitivetest;
public class TestedObjectClass {
    private InterfaceB interfaceB;
    public void runMe(boolean b) {
        interfaceB.foobar(b);
        interfaceB.foobar(b);
    }
}

So, obviously we want to test toe runMe-method and want to verify that the two calls on the interfaceB are actually done with the given arguments. Our first try was this code:

package de.matthiascoy.easymock.easymockprimitivetest;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.unitils.UnitilsJUnit4TestClassRunner;
import org.unitils.easymock.EasyMockUnitils;
import org.unitils.inject.annotation.InjectIntoByType;
import org.unitils.inject.annotation.TestedObject;

@RunWith(UnitilsJUnit4TestClassRunner.class)
public class EasyMockAndUnitilsTest {

    @TestedObject
    private TestedObjectClass testedObject;

    @InjectIntoByType
    private InterfaceB interfaceB;

    @Before
    public void setUp() {
        this.interfaceB = EasyMock.createMock(InterfaceB.class);
    }

    @Test(expected = AssertionError.class)
    public void testPrimitiveBoolean() {
        boolean B = true;

        interfaceB.foobar(B);
        EasyMock.expectLastCall();
        interfaceB.foobar(!B);
        EasyMock.expectLastCall();
        EasyMockUnitils.replay();

        testedObject.runMe(B);

        EasyMockUnitils.verify();
    }
}

What you can see is, that we do expect first TRUE and then FALSE, but that should fail. We do test that with the „expected=AssertionError“ value in the @Test annotation. But actually this tests fails, because there is no AssertionError. With just a „@Test“ the test just runs and shows us a green light. That’s very strange. So, we thought: must be a bug in the testingframework, but which one?

So, we created a EasyMock 3.2 only test

package de.matthiascoy.easymock.easymockprimitivetest;

import org.easymock.EasyMock;
import org.easymock.EasyMockRunner;
import org.easymock.EasyMockSupport;

import org.easymock.Mock;
import org.easymock.TestSubject;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(EasyMockRunner.class)
public class PureEasyMockTest extends EasyMockSupport {

    @TestSubject
    private TestedObjectClass testedObject = new TestedObjectClass();

    @Mock
    private InterfaceB interfaceBMock;

    @Test(expected = AssertionError.class)
    public void testPrimitiveBoolean() {
        boolean B = true;

        interfaceBMock.foobar(B);
        EasyMock.expectLastCall();
        interfaceBMock.foobar(!B);
        EasyMock.expectLastCall();

        replayAll();

        testedObject.runMe(B);

        verifyAll();
    }

    @Test(expected = AssertionError.class)
    public void testPrimitiveBooleanWithEq() {
        boolean B = true;

        interfaceBMock.foobar(EasyMock.eq(B));
        EasyMock.expectLastCall();
        interfaceBMock.foobar(EasyMock.eq(!B));
        EasyMock.expectLastCall();

        replayAll();

        testedObject.runMe(B);

        verifyAll();
    }
}

This test does work. So, easymock seems not to be the problem. Now, to unitils:

package de.matthiascoy.easymock.easymockprimitivetest;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.unitils.UnitilsJUnit4TestClassRunner;
import org.unitils.inject.annotation.InjectIntoByType;
import org.unitils.inject.annotation.TestedObject;
import org.unitils.mock.Mock;

@RunWith(UnitilsJUnit4TestClassRunner.class)
public class UnitilsTest {

    @TestedObject
    private TestedObjectClass testedObject;

    @InjectIntoByType
    private Mock<InterfaceB> interfaceB;

    @Test(expected = AssertionError.class)
    public void testPrimitiveBoolean() {
        boolean B = true;

        testedObject.runMe(B);

        interfaceB.assertInvoked().foobar(B);
        interfaceB.assertInvoked().foobar(!B);
    }
}

And this test just works fine as well. So, the problem must be somewhere in the middle. I’m still not sure where exactly, but the second call to interfaceB.foobar in EasyMockAndUnitilsTest.testPrimitiveBoolean does not care about the arguments. It does care about if it’s called or not, but the argument is ignored.

So, we decided to migrate all our tests to pure easymock. Maybe, somehow we will move to mockito at the end … maybe.