C# 单元测试:检查是否正在调用方法
我有以下课程:C# 单元测试:检查是否正在调用方法,c#,unit-testing,C#,Unit Testing,我有以下课程: public class MyClass { public void MyMethod() { try { ... save data to file ... } catch (Exception exception) { ErrorDisplay.ShowErrorMessage("My
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";
}
....
}
我需要在witch中编写一个单元测试,我将模拟IOException,我需要检查它
正在调用方法。有没有办法测试是否调用了一个方法?
或者是关于如何为我的案例进行单元测试的另一个想法
谢谢 测试静态方法很难。可以考虑将方法更改为非静态的。如果使用依赖项注入,这会容易得多。另一个选择是为商业TypeMock库购买许可证,该库允许您通过修改IL代码来模拟静态方法。这允许您编写代码来验证方法是否被调用、参数是什么等。您应该使用Moq或Rhino mock之类的模拟库 看看这个 对于静态方法,您可以使用
但是不是免费的您不能直接检查是否调用了一个方法,但是您可以将MyMethod中的主体提取到实现接口的单独类中,然后使用一些类似Rhinomock的模拟库来注入行为
使用RhinoMock,您可以指示mock抛出异常并期望调用 取决于您的模拟框架。没有一个免费的(Rhino、Moq)允许您对静态方法设定期望值。您需要购买一个商业产品,如Typemock或更好的产品,使ErrorDisplay类上的方法成为虚拟的,并将其实例传递给MyClass
例如,如果使用Moq,您可以发送一个
Mock
实例,并对其设置期望值。如上所述,使用静态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的现有调用,但它们现在更易于替换和测试
这不是一个完美的解决方案,但是,如果维护遗留代码,它可以让您添加一些可测试性,而无需进行重大的返工
对话框
在ErrorDisplay上运行单元测试还有一个问题;您将出现一个消息框。如果尝试在测试工具(或作为构建的一部分)中运行测试,则不太好
再说一次,间接是你的朋友。您可以将MessageBox.Show()调用替换为对MessageDisplayService.Show()的调用。默认实现可以调用消息框,一个虚拟的消息框可以用于测试(模拟或简单的不做任何事情实现)
单元测试
测试的单元边界是什么
从问题中可以看出,您希望对MyClass::MyMethod()运行测试,导致IOException并查看是否调用了GetIioSplayMessage()。如果我理解错误,请跳过下一节:)
您是否计划对可能发生IOException的每个类/方法执行此操作?
您是否计划对ErrorDisplay处理的每个其他异常类型可能发生的每个类/方法执行此操作
这是一项大量的工作,只需一次又一次地重新测试ErrorDisplay代码
我会看到的界限是
MyClass::MyMethod
如果发生异常,它将调用ErrorDisplay.阵雨RorMessage()并传入“MyMethod”和异常
之后的任何事情都是它无法控制的,不应该成为单元测试的一部分
错误显示。错误消息()
如果使用IOException调用它,那么它将显示通过调用GetIioSplayMessage()获得的消息
这独立于调用代码(如上所述),可以单独进行单元测试
ErrorDisplay.GetIODisplayMessage()
返回正确的错误消息。好的,如果该值是硬编码的,但显示了原理,则有点过头了
在测试MyClass::MyMethod时,我们希望验证当发生异常时,调用错误显示代码并传递正确的方法名和异常
在测试ErrorDisplay.阵雨RorMessage()时,我们验证是否为调用MessageDisplayService.Show()的异常类型获得了正确的消息
methodname+“:”+
我们不需要在这里测试IioSplayMessage的文本
测试ErrorDisplay.GetIioDisplayMessage()时,我们会检查它是否返回正确的消息
希望这是有用的
Alan。您应该避免使用静态类,而应该使用IoC和依赖项注入类型,因为它可以与静态方法一起工作。谢谢您的回答。这真的很有用。