Mockito在测试中途验证状态

时间:2011-07-07 16:29:46

标签: mockito

我有一些简单的代码,将对象设置为PROCESSING状态,执行一些操作,然后将其设置为SUCCESS。我想验证使用正确的值完成PROCESSING保存。

问题是当执行verify()测试时,对象在测试结束时调用.equals(),而不是在中途调用。

例如代码:

public void process(Thing thing) {
    thing.setValue(17);
    thing.setStatus(Status.PROCESSING);
    dao.save(thing);

    doSomeMajorProcessing(thing);

    thing.setStatus(Status.SUCCESS);
    dao.save(thing);
}

我想测试一下:

public void test() {
    Thing actual = new Thing();
    processor.process(actual);

    Thing expected = new Thing();
    expected.setValue(17);
    expected.setStatus(Status.PROCESSING);
    verify(dao).save(expected);

    // ....

    expected.setStatus(Status.SUCCESS);
    verify(dao).save(expected);
}

在第一次验证时,actual.getStatus()Status.SUCCESS,因为Mockito只保留对象的引用,并且最后只能测试它的值。

我已经考虑过如果when(...)所涉及的.equals()将在正确的时间被调用,结果只会在我想要它的时候发生。但是,在这种情况下,.save()不返回任何内容。

如何验证对象是否处于正确的状态?

4 个答案:

答案 0 :(得分:2)

好的,我找到了一个解决方案,但它非常可怕。验证对我来说不好,因为它运行得太晚,并且存根很难,因为该方法返回一个void。 但我可以做的是存根并抛出一个异常,如果调用了预期的东西,同时验证了某些东西被调用:

public void test() {
    Thing actual = new Thing();

    Thing expected = new Thing();
    expected.setValue(17);
    expected.setStatus(Status.PROCESSING);

    doThrow(new RuntimeException("save called with wrong object"))
            .when(dao).saveOne(not(expected));

    processor.process(actual);

    verify(dao).saveOne(any(Thing.class));

    // ....

    expected.setStatus(Status.SUCCESS);
    verify(dao).saveTwo(expected);
}

private <T> T not(final T p) {
    return argThat(new ArgumentMatcher<T>() {
        @Override
        public boolean matches(Object arg) {
            return !arg.equals(p);
        }
    });
}

这推断出预期被称为。唯一的缺点是难以验证该方法两次,但幸运的是,在我的情况下,两个DAO调用都采用不同的方法,因此我可以单独验证它们。

答案 1 :(得分:0)

argThat与hamcrest Matcher一起使用应该可以解决问题。如果事物具有thing状态,匹配器将匹配其传递的PROCESSING

public class ProcessingMatcher extends BaseMatcher<Thing> {
    @Override
    public boolean matches(Object item) {
        if (item instanceof Thing) {
            return ((Thing) item).getStatus() == Status.PROCESSING;
        }
        return false;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText(" has the PROCESSING status");
    }
}

然后在测试中,使用以下代码:

public class MyTest {

    public void test() {
        //...
        mockDao.save(argThat(hasTheProcessingStatus()));
    }

    static ProcessingMatcher hasTheProcessingStatus() {
        return new ProcessingMatcher();
    }
}

答案 2 :(得分:0)

Mockito在验证可变对象时遇到问题。有一个未解决的问题(http://code.google.com/p/mockito/issues/detail?id=126)

也许你应该切换到EasyMock。他们使用录音/播放模式并在通话时进行验证,与Mockito相反,Mockito会在通话后进行验证。

这个Mockito版本的测试有上述问题:

@Test
public void testMockito() {
    Processor processor = new Processor();
    Dao dao = Mockito.mock(Dao.class);
    processor.setDao(dao);

    Thing actual = new Thing();
    actual.setValue(17);
    processor.process(actual);

    Thing expected1 = new Thing();
    expected1.setValue(17);
    expected1.setStatus(Status.PROCESSING);
    verify(dao).save(expected1);

    Thing expected2 = new Thing();
    expected2.setValue(19);
    expected2.setStatus(Status.SUCCESS);
    verify(dao).save(expected2);
}

这个EasyMock版本运行良好:

@Test
public void testEasymock() {
    Processor processor = new Processor();
    Dao dao = EasyMock.createStrictMock(Dao.class);
    processor.setDao(dao);

    Thing expected1 = new Thing();
    expected1.setValue(17);
    expected1.setStatus(Status.PROCESSING);
    dao.save(expected1);

    Thing expected2 = new Thing();
    expected2.setValue(19);
    expected2.setStatus(Status.SUCCESS);
    dao.save(expected2);

    EasyMock.replay(dao);

    Thing actual = new Thing();
    actual.setValue(17);
    processor.process(actual);

    EasyMock.verify(dao);
}

在我的示例中doSomeMajorProcessingvalue设置为19。

private void doSomeMajorProcessing(Thing thing) {
    thing.setValue(19);     
}

答案 3 :(得分:0)

为什么不嘲笑Thing本身并验证?例如:

public class ProcessorTest {

    @Mock
    private Dao mockDao;
    @InjectMocks
    private Processor processor;

    @BeforeMethod   
    public void beforeMethod() {
        initMocks(this);
    }

    public void test() {

        Thing mockThing = Mockito.mock(Thing.class);
        processor.process(thing);

        verify(mockThing).setStatus(Status.PROCESSING);
        verify(mockThing).setValue(17);
        verify(mockDao).save(mockThing);
        verify(mockThing).setStatus(Status.SUCCESS);
    }

如果要显式测试这些事情发生的顺序,请使用InOrder对象:

public void inOrderTest() {

    Thing mockThing = Mockito.mock(Thing.class);
    InOrder inOrder = Mockito.inOrder(mockThing, mockDao);

    processor.process(mockThing);

    inorder.verify(mockThing).setStatus(Status.PROCESSING);
    inorder.verify(mockThing).setValue(17);
    inorder.verify(mockDao).save(mockThing);
    inorder.verify(mockThing).setStatus(Status.SUCCESS);
    inorder.verify(mockDao).save(mockThing);
}