我有一个应用程序,其中一个类被注册为消息侦听器,它接收来自队列的消息,检查它是否具有正确的类类型(在public void onMessage(Message message)
中)并将其发送到另一个转换为此类的类class to a string并将该行写入日志文件(在public void handleMessage(MessageType m)
中)。你会如何为此编写单元测试?
答案 0 :(得分:0)
如果您可以将Mockito与JUnit结合使用,那么您的测试可能如下所示:
public void onMessage_Success() throws Excepton {
// Arrange
Message message = aMessage().withContent("...").create();
File mockLogFile = mock(File.class);
MessageHandler mockMessageHandler = mock(MessageHandler.class);
when(mockMessageHandler).handleMessage(any(MessageType.class)
.thenReturn("somePredefinedTestOutput");
when(mockMessageHandler).getLogFile().thenReturn(mockLogFile);
MessageListener sut = spy(new MessageListener());
Whitebox.setInternalState(sut, "messageHanlder", mockMessageHandler);
// or simply sut.setMessageHandler(mockMessageHandler); if a setter exists
// Act
sut.onMessage(message);
// Assert
assertThat(mockLogFile, contains("your desired content"));
verify(sut, times(1)).handleMessage(any(Message.class));
}
请注意,这只是一个简单的示例,您可以如何测试它。可能有很多其他方法来测试功能。上面的示例展示了一个典型的构建器模式,用于生成接受某些测试值的默认消息。此外,我还没有真正澄清mockLogFile上contains
方法的Hamcrest匹配器。
正如@Keppil在他的评论中所提到的那样,创建多个测试用例是有意义的,这些测试用例在排列中略微变化并且断言测试坏案例的部分
我可能没有解释的是getLogFile()
方法(在您的应用程序中具有高确定性的另一个名称)MessageHandler
应该返回对MessageHandler实例使用的文件的引用存储实际的日志消息。因此,最好将此mockMessageHandler定义为spy(new MessageHandler())
而不是mock(MessageHandler.class)
,尽管这意味着单元测试实际上是一个集成测试,因为同时测试了两个类的交互。 / p>
但总的来说,我希望你有这个想法 - 如果你想要包含一个真实世界的对象,使用mock(Class)为你的被测系统(SUT)需要或间谍(实例)生成依赖关系的默认实现只有null值作为返回类型的一个。您可以使用when(...)。thenReturn(...)/。thenThrow(...)或doReturn(...)来影响模拟对象的返回值。如果(...)以防万一of void-operations fe
如果您已将依赖注入到私有字段中,则应使用Whitebox.setInternalState(...)
将值注入sut或mock类(如果没有public或package-private)(如果获得重用的测试模型)可以使用测试类中的系统测试类的包结构。可以使用setter-methods。
此外,verify(...)
允许您验证在执行SUT时是否调用了某个方法。在这种情况下,当实际的断言不是那么微不足道时,这非常方便。