在单元测试中使用模拟时如何避免重复代码

时间:2009-01-06 16:18:01

标签: unit-testing dependency-injection mocking rhino-mocks

我正在使用依赖注入来为我测试的类之外的代码提供模拟。我发现自己一遍又一遍地编写了大量相同的代码,因为我需要模拟我想要测试的方法中使用的AuthProvider,ConfigurationManager等。该方法包含分支(if-then-else),因此我有多个测试来测试该方法的所有执行路径。我几次实例化每个模拟(每个测试方法一次),但我想知道这是否是错误的方法? 另外,我提出了对模拟和预设响应的期望,显然主要是复制粘贴,因为在每个方法中调用AuthProvider.Authenticate()等调用

在每个方法中,我设置了一个模拟存储库,在每个方法的最后,我验证了模拟存储库。我是否应该有一些工厂来创建这些模拟并设置他们的期望和返回值?如果是这样的话?

为了实现模拟,我正在使用RhinoMocks。

5 个答案:

答案 0 :(得分:5)

“多次实例化每个模拟”不是问题。物品是免费的。

请确保您没有多次定义模拟类。课程很昂贵。

此外,您在TestCase中有一个“setUp”方法,允许您创建所有测试使用的fixture。是的,它是为每个测试重建的。不,这不是问题,除非它的速度很慢。

答案 1 :(得分:2)

假设您正在使用NUnit,您可以为Mocks使用实例变量,并在Setup / Teardown中重置它们。如果你看到重复的模式,那么你可以用生产代码做什么:重构和提取表达你想要实现的东西的辅助方法(如果根本没有共性,那么生产代码的设计就会出现问题)。 / p>

如果设置中存在重大分歧,请考虑为您的生产类编写多个测试类。

最后,考虑一下你的生产类是否太忙,一些行为应该被提取到一个辅助对象。

听取测试!

答案 2 :(得分:1)

这是我的看法..

我不会在这种情况下使用mock ...我会使用工厂方法返回类的伪实现并使用依赖注入来代替使用此实现。这样你就可以避免重复并可以重用这个实现再次n再次...这个工厂实现需要正确重构,即没有重复..

Mocks,我猜应该在你测试一些动态行为时使用..类似..当我在SUT上执行某些操作时调用了子系统中的一个方法..然后调用verify()来验证这种行为......还有一篇关于Martin Folwer bliki Mock Aren't Stubs

的文章

答案 3 :(得分:0)

您可能希望查看使用AAA样式的测试,以便使用常见设置进行多次测试。 Here's a decent example.

答案 4 :(得分:0)

如果您没有在模拟调用上设置期望,则像EasyMock这样的记录和重放框架会失败。但像Mockito这样的框架只记录所有调用,让你只验证那些重要的调用。因此,您不必在所有测试中对所有方法设置期望。

回到你在每个测试方法中实例化Mocks的问题,有一种比使用setUp()方法更好的方法。 Mockito提供@Mock注释。所以你声明你的变量(如字段),如: @Mock Repository repositoryMock

并在setUp()中调用initMocks()。声明的所有模拟对象在测试中自动可用,而无需显式创建Mocks。