繁体   English   中英

单元测试:Mocking framework vs Stub implementation

[英]Unit test: Mocking framework vs Stub implementation

给定需要使用特定服务的单元测试 class,似乎有不同的方法来伪造服务的行为,例如使用 mocking 框架,或实现存根 class。

例如,读/写磁盘的服务:

public interface FileServiceInterface {
  public void write(String text);
  public String read(String fileName);
}

我可能有一个 class 伪造它的行为,然后在测试 class 中使用它,注入存根而不是真正的实现:

public class FileServiceStub implements FileServiceInterface {
  ConcurrentHashMap<String, String> content = new ConcurrentHashMap<>();

  public void write(String fileName, String text) { 
    content.put(fileName, text); 
  }

  public String read(String fileName) { 
    return content.get(fileName); 
  }
}

另一种选择是让 Mockito(例如)在测试 class 中直接拦截对服务的调用:

public class TestExample {

  @Mock
  private FileServiceImpl service; // A real implementation of the service

  @Test
  void doSomeReadTesting() { 
    when(service.read(any(String.class))).thenReturn("something");
    ...
  }
}

我想知道这些替代方案中哪一个是最好的(或目前最被接受的)方法,以及是否有任何其他/更好的选择。 谢谢。

简短回答:取决于用例,当您需要检查行为时使用Mock否则在基于状态的测试使用Stub的情况下。
state 验证中,在提供所有必要的存根后,您让正在测试的 object 执行特定操作。 当它结束时,您检查 object 的 state 并验证它是预期的。
行为验证中,您确切指定要调用哪些方法,因此验证的不是结尾 state 是否正确,而是执行的步骤顺序是否正确。

Martin Fowler
文章模拟不是存根
有几种类型的伪装 object 用于代替真实的 object 用于测试目的:

  • 虚拟对象被传递但从未真正使用过。 通常它们只是用来填充参数列表。
  • 对象实际上有工作实现,但通常会采取一些捷径,这使得它们不适合生产(memory 数据库就是一个很好的例子)。
  • 存根为测试期间发出的呼叫提供固定答案,通常根本不响应测试编程之外的任何内容。
  • 间谍是存根,它们还根据它们的调用方式记录一些信息。 一种形式可能是 email 服务,它记录发送了多少消息。
  • Mocks对象预先编程为预期,这些预期形成了它们预期接收的调用的规范。

在您的情况下,我们有Fake vs Mock object 类型。 它们看起来都像真实的对象,但与Mocks不同的是,其他类型没有可能无法通过测试的预编程期望。 StubFake只关心最终的 state - 而不是 state 是如何派生的。
所以我们有两个不同的设计 styles 的测试。

基于 State 的测试更加黑盒化。 他们实际上并不关心被测系统 (SUT) 如何获得结果,只要它是正确的即可。 这使它们更能抵抗变化,并且与设计的耦合度更低。

但偶尔你确实会遇到一些很难使用state 验证的事情,即使它们不是尴尬的合作。 缓存就是一个很好的例子。 缓存的全部意义在于,您无法从其 state 判断缓存命中还是未命中——在这种情况下,行为验证将是一个明智的选择。

Mock的另一个好处是能够定义对期望的宽松约束——你可以使用any()anyString()withAnyArguments() 它是灵活的。

模拟和存根之间有什么区别?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM