我有一些简单的代码,将对象设置为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()
不返回任何内容。
如何验证对象是否处于正确的状态?
答案 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);
}
在我的示例中doSomeMajorProcessing
将value
设置为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);
}