我最近开始学习单元测试,并遇到了 Mockito 库。我读到了 @Mock 和 @Spy when() 等..
@Mock
Service service;
@Test
void test(){
when(service.runCode(Mock.anyString()).thenReturn("Working");
}
我在上面一行中的疑问是,
runCode(String a)
是否会被执行,或者一旦调用该方法,那么我在thenReturn()
部分中给出的内容将由模拟返回?
我正在尝试理解模拟
由于您是单元测试的新手,我将编写一个关于
Mocks
如何工作的简化说明。首先,重要的是要了解 dummies
、fakes
、mocks
、spies
只是不同类型的测试对象,它们看起来像您在生产中使用的实际对象。它们可以注入到您想要测试的组件中,以验证交互和/或返回一些测试数据。
要了解mockito在幕后做什么,您可以首先尝试基于公共接口编写自己的模拟:
public interface Service {
String runCode(String arg);
}
例如,您可以创建此 Service 接口的测试实现,无论传入的参数如何,它都将始终返回相同的硬编码值。这将是一个 Dummy:
public class DummyService implements Service {
@Override
public String runCode(String arg) {
return "dummy_response";
}
}
因此,您将能够在测试中使用它来避免运行实际的
runCode
方法。假设您有一个要测试的 Controller
类,该类在内部使用此 Service
,测试将如下所示:
@Test
void test() {
Controller c = new Controller(new DummyService());
var response = c.doSomething("abc");
// assert response ...
}
如您所见,虚拟对象相当“愚蠢”。有时您可能希望能够根据方法的输入返回不同的字符串。在这种情况下,您可以创建自己的Mock:
public class MockedService implements Service {
private Map<String, String> mockedData = new HashMap<>();
public void whenRunCodeThenReturn(String arg, String mockedResponse) {
mockedData.put(arg, mockedResponse);
}
@Override
public String runCode(String arg) {
return mockedData.get(arg);
}
}
现在,您必须实例化
MockedService
并根据测试的需要指定一些行为:
@Test
void test() {
MockedService mock = new MockedService();
Controller c = new Controller(mock);
mock.whenRunCodeThenReturn("abc", "mocked_response_for_abc");
var response = c.doSomething("abc");
// assert response ...
}
当然,mockito
是一个强大的框架,提供了更多的灵活性。它具有允许您为输入参数定义更复杂的条件的功能,它可以在每次测试后轻松重置模拟,并且不需要公共接口来代理对象。 有关假货、间谍和模拟等测试对象的更详细说明,请查看这篇文章:
https://medium.com/gitconnected/the-anatomy-of-mocks-in-unit-testing-3e6a78b2b5d3 https://site.mockito.org/