gpt4 book ai didi

java - 如何在返回 void 的方法上进行单元测试 "test the contract"?

转载 作者:行者123 更新时间:2023-11-30 08:03:22 27 4
gpt4 key购买 nike

这里是 Java 8,但这是一个(很可能)与语言无关的一般单元测试问题。

编写 JUnit 测试的语法很简单,但决定要编写什么测试如何测试主要/生产代码是我发现最重要的挑战。在阅读单元测试最佳实践时,我一遍又一遍地听到同样的话:

Test the contract

相信的想法是,单元测试不应该是脆弱的,并且如果方法的实现发生变化,则不一定会中断。该方法应该定义一个输入契约(Contract) -> 结果/结果,并且测试应该旨在验证契约(Contract)是否得到遵守。我想。

假设我有以下方法:

public void doFizzOnBuzz(Buzz buzz, boolean isFoobaz) {
// wsClient is a REST client for a microservice
Widget widget = wsClient.getWidgetByBuzzId(buzz.getId());

if(widget.needsFile()) {
File file = readFileFromFileSystem(buzz.getFile());

if(isFoobaz) {
// Do something with the file (doesn't matter what)
}
}

return;
}

private File readFileFromFileSystem(String filename) {
// Private helper method; implementation doesn't matter here EXCEPT...
// Any checked exceptions that Java might throw (as a result of working)
// with the file system are wrapped in a RuntimeException (hence are now
// unchecked.

// Reads a file from the file system based on the filename/URI you specify
}

所以在这里,我们有一个我们希望为 (doFizzOnBuzz) 编写单元测试的方法。这个方法:

  • 有两个参数,buzzisFoobaz
  • 使用类属性 wsClient 进行网络/REST 调用
  • 调用私有(private)辅助方法,该方法不仅适用于外部文件系统,而且“吞噬”已检查的异常;因此 readFileFromFileSystem 可能会抛出 RuntimeExceptions

我们可以为此编写什么样的单元测试来“测试合约”?

验证输入(buzzisFoobaz)是显而易见的;契约(Contract)应定义每个值/状态的有效值/状态,以及它们无效时应发生的异常/结果。

但除此之外,我什至不确定这里的“契约”是什么,这使得为其编写测试非常困难。所以我想这个问题真的应该类似于“我如何确定单元测试的契约是什么,然后你如何编写针对契约而非实现的测试?” p>

但是这个标题对于 SO 问题来说太长了。

最佳答案

您使用 doFizzOnBuzz(Buzz buzz, boolean isFoobaz)private File readFileFromFileSystem(String filename) 方法的代码不容易测试,因为第一种方法将尝试并读取一个文件,这不是你想在测试中做的事情。

在这里,doFizzOnBuzz 需要一些东西来提供一个文件供其使用。这个 FileProvider(我会这样调用它)可以是一个接口(interface),类似于:

public interface FileProvider {
File getFile(String filename);
}

在生产环境中运行时,会使用实际从磁盘读取文件的实现,但在单元测试 doFizzOnBuzz 时,可以使用 FileProvider 的模拟实现。这将返回一个模拟的 File

要记住的关键点是,在测试 doFizzOnBuzz 时,我们测试提供该文件的任何内容或任何其他内容。我们假设要正常工作。这些其他代码有它们自己的单元测试。

模拟框架,例如 Mockito可用于创建 FileProviderFile 的模拟实现,并将模拟 FileProvider 注入(inject)被测类,可能使用 setter:

public void setFileProvider(FileProvider f) {
this.fileProvider = f;
}

此外,我不知道什么是 wsClient,但我知道它有一个 getWidgetByBuzzId() 方法。这个类也可以是一个接口(interface),出于测试目的,接口(interface)将被模拟,并返回一个模拟的 Widget,类似于上面的 FileProvider。

使用 mockito,您不仅可以设置接口(interface)的模拟实现,还可以定义在该接口(interface)上调用方法时返回的值:例如

//setup mock FileProvider
FileProvider fp = Mockito.mock(FileProvider.class);

//Setup mock File for FileProvider to return
File mockFile = Mockito.mock(File.class);
Mockito.when(mockFile.getName()).thenReturn("mockfilename");
//other methods...

//Make mock FileProvider return mock File
Mockito.when(fp.getFile("filename")).thenReturn(mockFile);

ClassUnderTest test = new ClassUnderTest();
test.setFileProvider(fp); //inject mock file provider

//Also set up mocks for Buzz,, Widget, and anything else

//run test
test.doFizzOnBuzz(...)

//verify that FileProvider.getFile() was actually called:
Mockito.verify(fp).getFile("filenane");

如果没有使用参数 'filename' 调用 getFile(),则上述测试失败

结论如果您无法直接观察方法的结果,例如它是无效的,你可以使用Mocking来验证它与其他类和方法的交互。

关于java - 如何在返回 void 的方法上进行单元测试 "test the contract"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36328609/

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