如上所述,使用静态ErrorDisplay会导致一些测试和注入IErrorDisplay实现中的问题会解决其中的一些问题,但不是全部(请参阅下面的MessageBox)。然而...
静态+接口
如果你需要保持静态类ErrorDisplay,不想掏出了TypeMock你可以添加一个间接层
public interface IDisplayErrorImplementation {
void ShowErrorMessage(string message, Exception ex);
}
public class DefaultDisplayErrorImplementation : IDisplayErrorImplementation {
public void ShowErrorMessage(string message, Exception ex) {
//...
}
}
public static class DisplayError {
static DisplayError(){
Implementation = new DefaultDisplayErrorImplementation();
}
public static IDisplayErrorImplementation Implementation { get; set;}
public static void ShowErrorMessage(string message, Exception ex) {
Implementation.ShowErrorMessage(message, ex);
}
}
你得到以保持对ErrorDisplay的现有调用,但它们现在更易于替换和测试。
这不是一个完美的解决方案,但如果维护遗留代码,它可以让您添加一些可测试性,而无需做大的返工。
的MessageBox
你必须与ErrorDisplay运行单元测试的另一个问题;你将会出现一个MessageBox。如果试图在测试工具中运行测试(或作为构建的一部分),则效果不佳。
再次间接是你的朋友。您可以将MessageBox.Show()调用替换为对MessageDisplayService.Show()的调用。默认的实现可以调用消息框,一个虚拟的一个可以用于测试(无论是模拟或简单的无能为力实现)
单元测试
什么是测试你的单位的界限?
从问题看来,您希望针对MyClass :: MyMethod()运行测试,导致IOException,并看到GetIODisplayMessage()被调用。如果我误解了,请跳过下一节:)
您是否打算对发生IOException的每个类/方法执行此操作? 您是否打算为ErrorDisplay处理的每个其他异常类型都可能发生的每个类/方法执行此操作?
这是一个重复测试ErrorDisplay代码的很多工作。
我会看到的边界是
MyClass的::的MyMethod
如果出现异常,它调用ErrorDisplay.ShowErrorMessage()传递 “的MyMethod” 和异常。
之后的任何东西都不在其手中,不应该成为单元测试的一部分。
ErrorDisplay.ShowErrorMessage()
如果它被称为与一个IOException然后它表明,它得到通过调用GetIODisplayMessage()的消息。
这是调用代码的独立(如上所述),可以单独进行单元测试。
ErrorDisplay.GetIODisplayMessage()
返回正确的错误消息。好的,如果这个值是硬编码,但是显示了原理,那么有点矫枉过正。
当测试MyClass :: MyMethod时,我们要验证发生异常时,错误显示代码被称为传入正确的方法名称和异常。
当测试ErrorDisplay.ShowErrorMessage(),我们确认我们得到我们与 方法名调用MessageDisplayService.Show()的异常类型正确的消息+“:” + <> 我们并不需要测试这里是IODisplayMessage的文本。
测试ErrorDisplay.GetIODisplayMessage()时,我们检查它是否返回正确的消息。
希望这是有用的,
艾伦。
感谢您的回答。这真的很有用。 – paccic