2010-02-12 71 views
6

单元测试代码库时,我需要使用模拟对象的迹象是什么?单元测试void方法/嘲讽对象迹象标记

这是否会像查看对代码库中其他对象的大量调用一样简单?

另外,我将如何测试不返回值的方法?所以,如果我的方法返回void但打印到一个文件,我只是检查文件的内容?

嘲笑是为了外部的依赖,所以这是从字面上的一切,不是?文件系统,分贝,网络等...

+0

为了您的最后一点检查:http://martinfowler.com/articles/mocksArentStubs.html只是为了确保你意识到不同之处。 – Finglas 2010-02-12 23:32:13

+0

下面是一些很好的解决方案,可以解决其中一些问题:http://xunitpatterns.com/TestStrategy.html – 2010-02-18 22:12:10

回答

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 
} 

对我的事情是,如果我尝试测试大量的类作为一个大水珠,然后有通常的设置代码吨。当你试图让你的头部绕过所有的依赖关系时,这不仅会令你感到困惑,而且在需要做出更改时非常脆弱。

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

+4

您最终将绑定测试与内部实现细节进行对比,这意味着它们往往会更频繁地中断。使用基于状态的测试,您只关心输出。嘲笑通常更难以建立,但他们当然在单元测试中占有一席之地。 – Finglas 2010-02-12 23:45:16

-1

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

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

总之,嘲笑是最好的利用,当你在等待别人,需要的东西,以完成你的工作。

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

+0

-1 - 这是基于对嘲笑和存根的误解。虽然你在做TDD时肯定会删除功能,但这不是模拟对象的用途。你不嘲笑被测试的对象,你嘲笑它的依赖关系。 – TrueWill 2010-02-18 22:17:24

+0

是的,我想在存根和嘲is之间是有区别的。我想你误解了我说的话。在第一段中,我描述了什么是单元测试,以及如何使用您创建的对象来模拟您目前无法访问或无意访问的实际对象。在第二段中,我开始描述mock是用于集成测试的......但我错了。集成测试在单元测试之后完成,并且用真实对象完成,而不是嘲笑。无论哪种方式,当你想在集成之前进行单元测试时,最好使用mock。 – 2010-02-18 22:51:12

0

Mocks/stubs/fakes/test double/etc。单元测试没问题,并且允许单独测试被测试的类/系统。集成测试可能不会使用任何模拟;他们实际上击中了数据库或其他外部依赖项。

您必须使用模拟或存根。通常这是因为您要测试的类对接口有依赖性。对于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建议),而我只是在测试断言对系统(I类”的实例m测试)。如本例所示,我可能会检查属性值(状态)或方法的返回值。

我推荐读The Art of Unit Testing,尤其是如果你使用.NET。