提问人:bokabokaboka 提问时间:10/30/2023 最后编辑:ndc85430bokabokaboka 更新时间:10/30/2023 访问量:51
如何在不中断正在测试的代码的情况下注入假货
How to inject a fake without disrupting the code being tested
问:
以下是《单元测试的艺术,第二版》一书的原文: 提取接口以允许替换底层实现
- 在这种技术中,您需要分解触及 file系统添加到一个单独的类中。这样你就可以很容易地区分 它,然后替换测试中对该类的调用(就像原来一样 如图 3.3 所示)。第一个列表显示了您 需要更改代码。
清单 3.1 解压一个触及文件系统的类并调用它
public bool IsValidLogFileName(string fileName)
{
FileExtensionManager mgr =
new FileExtensionManager();
return mgr.IsValid(fileName);
}
class FileExtensionManager
{
public bool IsValid(string fileName)
{
//read some file here
}
}
- 接下来,您可以告诉被测类,而不是使用 具体的 FileExtensionManager 类,它将处理某种形式的 ExtensionManager,但不知道它的具体实现。 In.NET,这可以通过使用基类或 FileExtensionManager 将扩展的接口。下一个上市 展示了在设计中使用新界面以使其更 可测试。图 3.4 显示了此实现的示意图。
清单 3.2 从已知类中提取接口
public class FileExtensionManager : IExtensionManager
{
public bool IsValid(string fileName)
{
//read some file here
}
}
public interface IExtensionManager
{
bool IsValid (string fileName);
}
//the unit of work under test:
public bool IsValidLogFileName(string fileName)
{
IExtensionManager mgr =
new FileExtensionManager();
return mgr.IsValid(fileName);
}
请注意,“IsValidLogFileName”方法中的“IExtensionManager mgr = new FileExtensionManager();”会导致稍后出现问题。
清单 3.4 使用构造函数注入注入存根
public class LogAnalyzer
{
private IExtensionManager manager;
public LogAnalyzer(IExtensionManager mgr)
{
manager = mgr;
}
public bool IsValidLogFileName(string fileName)
{
return manager.IsValid(fileName); //The tested code has been disrupted; 'IExtensionManager mgr = new FileExtensionManager();' has been deleted!!!!!
}
}
public interface IExtensionManager
{
bool IsValid(string fileName);
}
[TestFixture]
public class LogAnalyzerTests
{
[Test]
public void
IsValidFileName_NameSupportedExtension_ReturnsTrue()
{
FakeExtensionManager myFakeManager =
new FakeExtensionManager();
myFakeManager.WillBeValid = true;
LogAnalyzer log =
new LogAnalyzer (myFakeManager);
bool result = log.IsValidLogFileName("short.ext");
Assert.True(result);
}
}
internal class FakeExtensionManager : IExtensionManager
{
public bool WillBeValid = false;
public bool IsValid(string fileName)
{
return WillBeValid;
}
}
请注意上面的 IsValidLogFileName 方法。虽然修改允许测试代码正常运行,但测试代码已被中断;“IExtensionManager mgr = new FileExtensionManager();”已被删除。
这会破坏源代码功能的完整性。当我们正常运行源代码时,程序将无法正确调用 FileExtensionManager 类的 IsValid 方法!您不会得到清单 3.2 中所示的相同结果。如果我想恢复源代码,我应该在第 3.4 行中将“IExtensionManager mgr = new FileExtensionManager();”放在什么位置?以便代码在运行时调用 FileExtensionManager 类的 IsValid 方法,并在测试期间调用 FakeExtensionManager 类的 IsValid 方法
答:
无论你用什么来创建一个新的实例,都应该创建一个类的适当实例,该类通过构造函数实现和注入它。LogAnalyzer
IExtensionManager
就像你的测试正在实例化和注入一个假的一样,你的真实代码应该实例化并注入一个真实的实例。这可以使用 IoC 容器或“纯 DI”。
要回答该问题,请执行以下操作:
...我应该把'IExtensionManager mgr = new FileExtensionManager()放在哪里?
您可以在“组合根”中执行此操作。
评论