单元测试void方法/模拟对象告诉标志

时间:2010-02-12 23:22:15

标签: unit-testing mocking

在单元测试代码库时,我需要使用模拟对象的迹象是什么?

这会像在代码库中看到很多对其他对象的调用一样简单吗?

另外,我如何单元测试不返回值的方法?因此,如果我的方法返回void但打印到文件,我只检查文件的内容吗?

模拟是针对外部依赖的,所以这就是一切,不是吗?文件系统,数据库,网络等...

3 个答案:

答案 0 :(得分:2)

如果有的话,我可能会过度使用嘲笑。

每当一个类调用另一个类时,通常我会模拟该调用,并且我验证调用是否使用了正确的参数。否则,我将进行单元测试,检查被模拟对象的具体代码是否正确。

示例:

[Test]
public void FooMoo_callsBarBaz_whenXisGreaterThan5()
{
    int TEST_DATA = 6;
    var bar = new Mock<Bar>();
    bar.Setup(x => x.Baz(It.Is<int>(i == TEST_DATA)))
       .Verifiable();

    var foo = new Foo(bar.Object);

    foo.moo(TEST_DATA);

    bar.Verify();
}

...
[Test]
public void BarBaz_doesSomething_whenCalled()
{
   // another test
}

对我而言,如果我尝试将大量的类作为一个大型的全局测试,那么通常会有大量的设置代码。当您试图了解所有依赖关系时,这不仅令人困惑,而且在需要进行更改时非常脆弱。

我更喜欢小的简洁测试。更容易编写,更易于维护,更容易理解测试的意图。

答案 1 :(得分:0)

模拟/存根/假货/测试双打/等。在单元测试中很好,并允许单独测试被测试的类/系统。集成测试可能不会使用任何模拟;他们实际上打了数据库或其他外部依赖。

必要时使用模拟或存根。通常这是因为您尝试测试的类依赖于接口。对于TDD,您希望编程接口而不是实现,并使用依赖注入(一般来说)。

一个非常简单的案例:

public class ClassToTest
{
   public ClassToTest(IDependency dependency)
   {
      _dependency = dependency;
   }

   public bool MethodToTest()
   {
      return _dependency.DoSomething();
   }
}

IDependency是一个接口,可能是一个昂贵的调用(数据库访问,Web服务调用等)。测试方法可能包含类似于以下的代码:

// Arrange

var mock = new Mock<IDependency>();

mock.Setup(x => x.DoSomething()).Returns(true);

var systemUnderTest = new ClassToTest(mock.Object);

// Act

bool result = systemUnderTest.MethodToTest();

// Assert

Assert.That(result, Is.True);

请注意,我正在进行状态测试(如@Finglas建议的那样),而我只是针对被测系统(我正在测试的类的实例)断言。我可以检查属性值(state)或方法的返回值,如本例所示。

我建议您阅读The Art of Unit Testing,特别是如果您使用的是.NET。

答案 2 :(得分:-1)

单元测试仅适用于在自身内部自主运行的一段代码。这意味着它不依赖于其他对象来完成其工作。如果您正在进行测试驱动编程或测试优先编程,则应该使用模拟。您将创建一个您将要创建的函数的模拟(或我喜欢称之为存根),并为测试通过设置某些条件。最初函数返回false并且测试失败,这是预期的...然后你编写代码来完成实际工作直到它通过。

但我认为你指的是集成测试,而不是单元测试。在这种情况下,如果您正在等待其他程序员完成他们的工作并且您当前无法访问他们正在创建的功能或对象,则应该使用模拟。如果您知道界面,希望您这样做,否则嘲笑是毫无意义的,浪费时间,那么您可以创建一个您希望将来获得的简化版本。

简而言之,当你等待别人并需要一些东西来完成你的工作时,最好利用嘲笑。

如果可能,您应该尝试始终返回值。有时您会遇到已经返回的问题,但在C和C ++中,您可以使用输出参数,然后使用返回值进行错误检查。