gpt4 book ai didi

java - Mockito 测试 void 方法

转载 作者:IT老高 更新时间:2023-10-28 21:00:27 36 4
gpt4 key购买 nike

我有以下代码要测试:

public class MessageService {
private MessageDAO dao;

public void acceptFromOffice(Message message) {
message.setStatus(0);
dao.makePersistent(message);

message.setStatus(1);
dao.makePersistent(message);

}
public void setDao (MessageDAO mD) { this.dao = mD; }
}

public class Message {
private int status;
public int getStatus () { return status; }
public void setStatus (int s) { this.status = s; }

public boolean equals (Object o) { return status == ((Message) o).status; }

public int hashCode () { return status; }
}

我需要验证,acceptFromOffice 方法确实将状态设置为 0,而不是持久化消息,然后将其状态更改为 1,然后再次持久化。

使用 Mockito,我尝试了以下操作:

@Test
public void testAcceptFromOffice () throws Exception {

MessageDAO messageDAO = mock(MessageDAO.class);

MessageService messageService = new MessageService();
messageService.setDao(messageDAO);

final Message message = spy(new Message());
messageService.acceptFromOffice(message);

verify(messageDAO).makePersistent(argThat(new BaseMatcher<Message>() {
public boolean matches (Object item) {
return ((Message) item).getStatus() == 0;
}

public void describeTo (Description description) { }
}));

verify(messageDAO).makePersistent(argThat(new BaseMatcher<Message>() {
public boolean matches (Object item) {
return ((Message) item).getStatus() == 1;
}

public void describeTo (Description description) { }
}));

}

我实际上在这里希望验证将验证调用两次 makePersistent 方法具有不同的 Message 对象的状态。但它没有说

Argument(s) are different!

有什么线索吗?

最佳答案

测试您的代码并非易事,但并非不可能。我的第一个想法是使用 ArgumentCaptor ,与 ArgumentMatcher 相比,它更易于使用和理解。 .不幸的是,测试仍然失败 - 原因肯定超出了这个答案的范围,但如果你感兴趣,我可能会提供帮助。我仍然觉得这个测试用例很有趣,可以展示(不正确的解决方案):

@RunWith(MockitoJUnitRunner.class)
public class MessageServiceTest {

@Mock
private MessageDAO messageDAO = mock(MessageDAO.class);

private MessageService messageService = new MessageService();

@Before
public void setup() {
messageService.setDao(messageDAO);
}

@Test
public void testAcceptFromOffice() throws Exception {
//given
final Message message = new Message();

//when
messageService.acceptFromOffice(message);

//then
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);

verify(messageDAO, times(2)).makePersistent(captor.capture());

final List<Message> params = captor.getAllValues();
assertThat(params).containsExactly(message, message);

assertThat(params.get(0).getStatus()).isEqualTo(0);
assertThat(params.get(1).getStatus()).isEqualTo(1);
}

}

不幸的是,有效的解决方案需要稍微复杂地使用 Answer .简而言之,不是让 Mockito 记录和验证每次调用,而是提供一种回调方法,每次测试代码执行给定的 mock 时都会执行。在这个回调方法(我们示例中的 MakePersistentCallback 对象)中,您可以访问两个参数并且可以更改返回值。这是一门重型大炮,您应该小心使用它:

    @Test
public void testAcceptFromOffice2() throws Exception {
//given
final Message message = new Message();
doAnswer(new MakePersistentCallback()).when(messageDAO).makePersistent(message);

//when
messageService.acceptFromOffice(message);

//then
verify(messageDAO, times(2)).makePersistent(message);
}


private static class MakePersistentCallback implements Answer {

private int[] expectedStatuses = {0, 1};
private int invocationNo;

@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
final Message actual = (Message)invocation.getArguments()[0];
assertThat(actual.getStatus()).isEqualTo(expectedStatuses[invocationNo++]);
return null;
}
}

该示例尚未完成,但现在测试成功了,更重要的是,当您更改 CUT 中的几乎任何内容时,测试会失败。如您所见,每次调用模拟 messageService.acceptFromOffice(message) 时都会调用 MakePersistentCallback.answer 方法。在 naswer 中,您可以执行所有您想要的验证。

注意:请谨慎使用,维护此类测试至少可以说很麻烦。

关于java - Mockito 测试 void 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5249920/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com