我应该在课堂上添加功能以使其可测试吗?

时间:2012-06-19 20:18:09

标签: unit-testing testing automated-tests

我仍然试图了解单元测试,我有一个简单的问题。今天我想为一个非常简单的函数编写一个测试。这个功能正是这样做的:

void OnSomething()
{
   increment++;

   if (increment == 20)
     SaveIt();
}

我说过,这个功能可以测试。我可以编写一个调用它20次的测试,然后验证是否已经调用了SaveIt。

然后我怀疑了。如何测试已调用SaveIt?我的第一个答案是添加一个布尔值,但后来我想:添加类功能只是为了让它可测试是否正确?

请指教。谢谢。

2 个答案:

答案 0 :(得分:3)

我建议让SaveIt返回成功或失败的结果,这样可以更容易地进行整体测试。你可以做一些简单的操作,让它返回一个bool,或者你可以创建一个通用的结果类,它包含设置消息的能力,如果你需要报告它是通过还是失败。

一个简单的示例

public class Result
{
   public bool IsSuccess;
   public List<string> Messages;
}

在单元测试中,您尝试仅测试OnSomething行为 - 不应测试“SaveIt”内部发生的情况。理想情况下,你希望SaveIt()出现在另一个类中,这样你就可以模拟它的响应。

我为此目的使用Moq。 Moq是免费的,你可以在这里得到它:http://code.google.com/p/moq/

我的方法将成为

Result OnSomething()
{
    Result result=null;
    increment++;
    if(increment == 20)
    {
         result = saver.SaveIt();
    }
    return result;
}

您的类构造函数将采用一个实现ISaver接口的对象(定义SaveIt()方法)(理想情况下由DI框架注入,但如果必须,可以手动生成它。)

现在在您的单元测试中,您将创建一个模拟版本的ISaver并告诉它在被调用时返回什么:

 Mock<ISaver> mock = new Mock<ISaver>();
 mock.Setup(x=> x.SaveIt()).Returns(new Result{IsSuccess=true});

您将在构造函数ISaver参数中实例化类传递mock.Object。

离。

 MyClass myClass = new MyClass(mock.Object);  
 //(assuming it didn't have other parameters)

然后,你可以断言结果是否为null - 如果它从未被调用过,它将为null,因为你上面做的设置永远不会触发。

 (in nunit)
 Result result = myClass.OnSomething();
 Assert.IsNotNull(result);

如果你真的不希望OnSomething()返回结果,或者因为它是一个事件而不能,那么我会让OnSomething()调用一个方法来为你完成工作:

 void OnSomething()
 {
      Result result = DoTheWork();
 }

 Result DoTheWork()
 {
    Result result=null;
    increment++;
    if(increment == 20)
    {
         result = saver.SaveIt();
    }
    return result;
 }

然后在DoTheWork()而不是OnSomething()上运行单元测试。

答案 1 :(得分:2)

绝对不是!生产代码根本不应该依赖于测试,但测试应该验证实际代码的正确行为。这可以通过多种方法实现,例如IOC和使用mocks。您可以查看一些可以简化您生活的现有框架: