当构造函数有参数时用Moq模拟对象


92

我有一个要尝试使用最小起订量模拟的对象。对象的构造函数具有必需的参数:

public class CustomerSyncEngine {
    public CustomerSyncEngine(ILoggingProvider loggingProvider, 
                              ICrmProvider crmProvider, 
                              ICacheProvider cacheProvider) { ... }
}

现在,我正在尝试使用moq的v3“设置”或v4“ Mock.Of”语法为此对象创建模拟,但无法弄清楚……我尝试的所有操作均未通过验证。这是我到目前为止的内容,但是最后一行是给我一个真实的对象,而不是模拟对象。我这样做的原因是因为我要验证的CustomerSyncEngine上有一些方法正在被调用...

// setup
var mockCrm = Mock.Of<ICrmProvider>(x => x.GetPickLists() == crmPickLists);
var mockCache = Mock.Of<ICacheProvider>(x => x.GetPickLists() == cachePickLists);
var mockLogger = Mock.Of<ILoggingProvider>();

// need to mock the following, not create a real class like this...
var syncEngine = new CustomerSyncEngine(mockLogger, mockCrm, mockCache);

您能否提供一个希望验证被调用的示例方法?
Ciaran 2012年

4
因此,如果我具有对类的依赖关系,而不是对接口的依赖关系,则必须模拟它们的依赖关系,这将递归地减少。最后,即使我不需要代码中的接口,我也不得不使用某些接口来使我的代码可测试。我认为太多的接口比嘲讽具体的类更难闻……
Tarion

Answers:


34

最后一行是给您一个真实的实例,因为您使用的是new关键字,而不是嘲笑CustomerSyncEngine。

你应该用 Mock.Of<CustomerSyncEngine>()

模拟具体类型的唯一问题是Moq需要一个公共默认构造函数(不带参数),或者您需要使用构造函数arg规范创建Moq。http://www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html

最好的办法是右键单击您的班级,然后选择“提取”界面。


3
关于此问题,一种替代方法是使用自动模拟容器。我最喜欢的是Machine.Fakes与Machine.Specifications一起使用自动模拟容器,可以更轻松地测试较小的表面积。假设安德鲁需要测试一种方法,CustomerSyncEngine因为ICrmProvider必须为所有3个接口提供仅与传统的模拟实现一起使用,而自举容器将仅允许您提供一个。
克里斯·马里西奇

73

将最后一行更改为

var syncEngine = new Mock<CustomerSyncEngine>(mockLogger, mockCrm, mockCache).Object;

它应该工作


3
不确定此评论如何适用于我的答案?
Suhas

2
因为这会导致编译错误,因为嘲笑了mockLogger,其他人则抛出了一个异常,即它们没有Object属性
Justin Pihony 2013年

2
因为OP使用Mock.Of <T>()创建记录器,crm和缓存类型的模拟,所以返回的对象以T而不是Mock <T>的形式返回。因此,将它们提供给CustomerSyncEngine的Mock时,无需使用mockLogger.Object等,并且如@JustinPihony所述,应该向您显示设计时错误。
乔什·古斯特

1
@suhas不应该是他new Mock<CustomerSyncEngine>(new object[]{mockLogger, mockCrm, mockCache}).Object;
GiriB

@GiriB不是必需的,但有可能,因为模拟是用Params定义的。公共模拟(params对象[]参数)
JIRÍHerník
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.