您的问题向刚接触开发人员的测试暴露了最困难的部分之一:
“我到底要测试什么?”
您的示例不是很有趣,因为它只是将一些API调用粘合在一起,因此,如果您要为其编写单元测试,则最终只能断言方法已被调用。像这样的测试将您的实现细节与测试紧密结合在一起。这很不好,因为现在每次更改方法的实现细节都必须更改测试,因为更改实现细节会破坏您的测试!
实际上,进行不良测试比根本不进行测试更糟糕。
在您的示例中:
void DoIt(IZipper zipper, IFileSystem fileSystem, IDllRunner runner)
{
string path = zipper.Unzip(theZipFile);
IFakeFile file = fileSystem.Open(path);
runner.Run(file);
}
尽管您可以传递模拟,但测试方法中没有逻辑。如果要对此进行单元测试,它可能看起来像这样:
// Assuming that zipper, fileSystem, and runner are mocks
void testDoIt()
{
// mock behavior of the mock objects
when(zipper.Unzip(any(File.class)).thenReturn("some path");
when(fileSystem.Open("some path")).thenReturn(mock(IFakeFile.class));
// run the test
someObject.DoIt(zipper, fileSystem, runner);
// verify things were called
verify(zipper).Unzip(any(File.class));
verify(fileSystem).Open("some path"));
verify(runner).Run(file);
}
恭喜,您基本上将DoIt()
方法的实现细节复制粘贴到了测试中。维护愉快。
当你写测试,要考什么,而不是如何。
有关更多信息,请参见黑匣子测试。
在什么是你的方法的名称(或至少应该是)。该如何为所有的小细节时住在你的方法内。良好的测试让你换出如何不破坏什么。
这样考虑一下,问自己:
“如果我更改此方法的实现细节(而不更改公共合同),是否会破坏我的测试?”
如果答案是肯定的,你正在测试的如何,而不是什么。
为了回答有关测试具有文件系统依赖性的代码的特定问题,假设您对文件进行了一些更有趣的操作,并且想要将Base64编码的内容保存byte[]
到文件中。您可以使用流为这个来测试你的代码做正确的事,而不必检查怎么它做它。一个示例可能是这样的(在Java中):
interface StreamFactory {
OutputStream outStream();
InputStream inStream();
}
class Base64FileWriter {
public void write(byte[] contents, StreamFactory streamFactory) {
OutputStream outputStream = streamFactory.outStream();
outputStream.write(Base64.encodeBase64(contents));
}
}
@Test
public void save_shouldBase64EncodeContents() {
OutputStream outputStream = new ByteArrayOutputStream();
StreamFactory streamFactory = mock(StreamFactory.class);
when(streamFactory.outStream()).thenReturn(outputStream);
// Run the method under test
Base64FileWriter fileWriter = new Base64FileWriter();
fileWriter.write("Man".getBytes(), streamFactory);
// Assert we saved the base64 encoded contents
assertThat(outputStream.toString()).isEqualTo("TWFu");
}
该测试使用ByteArrayOutputStream
,但在应用程序(使用依赖注入)的实际StreamFactory(也许叫FileStreamFactory)将返回FileOutputStream
距离outputStream()
,并会写入File
。
write
这里的方法有趣的是,它是将内容写成Base64编码的,因此我们对此进行了测试。对于您的DoIt()
方法,将使用集成测试对其进行更适当的测试。