2011-07-07 29 views
1

我有一些简单的代码,将对象设置为PROCESSING状态,执行一些操作,然后将其设置为SUCCESS。我想验证PROC​​ESSING保存是否使用了正确的值。Mockito通过测试中途验证状态

问题是执行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()将在正确的时间被调用,并且结果只会发生在Thing是我想要的东西时。但是,在这种情况下,.save()不会返回任何内容。

如何验证对象是否进入正确的状态?

回答

0

使用argThat与hamcrest匹配应该做的伎俩。匹配器将匹配其通过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(); 
    } 
} 
+0

你能解释一下,你就会把你的匹配,解决了什么问题? – Steve

+0

@Steve:我编辑我的答案是更明确。 –

+0

您是否缺少verify()或when()?我不明白Matcher是如何在测试结束时解决验证问题的,而不是半途而废。 – Steve

0

具有的Mockito验证可变对象的问题。有关于这(http://code.google.com/p/mockito/issues/detail?id=126)

一个开放的问题,也许你应该切换到EasyMock的。他们使用录制/回放模式,并在通话时进行验证,与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);  
} 
2

好的,我找到了一个解决方案,但它非常好rible。确认没有对我好,因为它运行为时已晚,磕碰是困难的,因为该方法返回一个空。 但我能做的就是存根和抛出一个异常,如果任何事情,但预期被调用时,在验证的东西叫做:

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调用是不同的方法,这样我就可以单独验证。

0

为什么不只是嘲笑事情本身,并验证?例如:

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); 
    } 

如果你想明确地测试中,这些事情发生的顺序,使用序对象:

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); 
}