单元测试:检查一个方法是否被调用
本文关键字:方法 一个 是否 调用 检查 单元测试 | 更新日期: 2023-09-27 18:11:27
我有以下类:
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()
方法。是否有一种方法来测试一个方法是否被调用?或者关于如何为我的案例做单元测试的另一个想法?
谢谢。
如上所述,使用静态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的现有调用,但它们现在更易于替换和可测试。
这不是一个完美的解决方案,但是,如果维护遗留代码,它可以让您添加一些可测试性,而无需进行主要的返工。
<标题>弹出窗口h1> ErrorDisplay上运行单元测试有另一个问题;您将出现一个消息框。如果试图在测试工具中运行测试(或作为构建的一部分),则不是很好。再次强调,间接是你的朋友。您可以将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()的异常类型的正确消息Methodname + ":" + <>我们不需要测试IODisplayMessage的文本。
当测试ErrorDisplay.GetIODisplayMessage()时,我们检查它是否返回正确的消息。
希望这是有用的,
Alan。标题>标题>您不能直接检查是否正在调用方法,但是您可以将MyMethod中的主体提取到实现接口的单独类中,然后使用一些模拟库(如RhinoMocks)注入该行为。
使用RhinoMock,您可以指示模拟抛出异常并期望调用。
测试静态方法是困难的。您可以考虑将方法更改为非静态的。如果使用依赖注入,这要容易得多。另一种选择是购买商业TypeMock库的许可,该库允许您通过修改IL代码来模拟静态方法。这允许您编写代码来验证方法是否被调用,参数是什么,等等。
取决于您的mock框架。没有一个免费的(Rhino, Moq)允许你对静态方法设置期望。你需要购买一个商业产品,比如Typemock,或者最好还是让ErrorDisplay类上的方法是虚的,并把它的一个实例传递给MyClass。
作为一个例子,如果你使用Moq,你可以发送一个Mock<ErrorDisplay>
的实例,并设置一个期望。
您应该使用mock库,例如Moq或Rhino mock看这个Moq
对于静态方法,可以使用TypeMock Isolator
但不是自由的