2011-10-14 88 views
3

我有以下类别:单元测试:检查是否被调用的方法

public class MyClass 
{ 
    public void MyMethod() 
    { 
     try 
     { 
      ... 
      save data to file 
      ... 
     } 
     catch (Exception exception) 
     { 
      ErrorDisplay.ShowErrorMessage("MyMethod", exception); 
     } 
    } 
} 

public class ErrorDisplay 
{ 
    public static ShowErrorMessage(string methodName, Exception exception) 
    { 
     if (exception is IOException) 
      MessageBox.Show(methodName + " : " + GetIODisplayMessage()); 
     else if ... 
      ... 
     else 
      ... 
    } 

    public static string GetIODisplayMessage() 
    { 
     return "IO error"; 
    } 

    .... 
} 

我需要写在巫单元测试,我会嘲笑IOException异常,我需要检查 GetIODisplayMessage()方法被称为。有没有办法测试一个方法是否被调用? 或者也许另一个想法如何为我的情况进行单元测试?

谢谢。

回答

3

如上所述,使用静态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()时,我们检查它是否返回正确的消息。

希望这是有用的,

艾伦。

+0

感谢您的回答。这真的很有用。 – paccic

0

测试静态方法很难。你可以考虑改变你的方法是非静态的。如果使用依赖注入,这会更容易。另一种选择是购买商业TypeMock库的许可证,这将允许您通过修改IL代码来模拟静态方法。这使您可以编写代码来验证该方法被调用,什么论据等

0

您应该使用嘲讽库如起订量或犀牛嘲笑 看看这个Moq

静态方法你可以使用TypeMock Isolator

,但不是免费的

+0

这些都不能用于静态类或方法。 –

+0

您应该避免使用静态类来代替使用IoC和依赖注入类型模拟隔离器可以使用静态方法 – Serghei

1

不能直接检查,如果被调用的方法,但你可以提取的MyMethod身体成一个单独的类实现一个接口,然后使用像RhinoMocks一些模拟库注射等行为。

使用RhinoMock,您可以指示模拟引发异常并期待invokations。

0

取决于你的嘲笑框架。免费的(Rhino,Moq)都不允许你设置静态方法的期望值。您需要购买Typemock等商业产品,或者更好地将ErrorDisplay类中的方法虚拟化并将其实例传递给MyClass。

举个例子,如果使用Moq并设置了期望值,那么你可以发送一个Mock<ErrorDisplay>的实例。

相关问题