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

And*_*ell 82 moq

我有一个对象,我正在尝试使用moq进行模拟.对象的构造函数具有必需参数:

public class CustomerSyncEngine {
    public CustomerSyncEngine(ILoggingProvider loggingProvider, 
                              ICrmProvider crmProvider, 
                              ICacheProvider cacheProvider) { ... }
}
Run Code Online (Sandbox Code Playgroud)

现在我正在尝试使用moq的v3"setup"或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);
Run Code Online (Sandbox Code Playgroud)

Suh*_*has 60

将最后一行更改为

var syncEngine = new Mock<CustomerSyncEngine>(mockLogger, mockCrm, mockCache).Object;
Run Code Online (Sandbox Code Playgroud)

它应该工作

  • 不确定此评论如何适用于我的答案? (3认同)
  • 因为这会导致编译错误,因为mockLogger和其他人会抛出一个异常,他们没有Object属性 (2认同)
  • 因为OP使用Mock.Of <T>()来创建记录器,crm和缓存类型的模拟,所返回的对象将返回为T,而不是Mock <T>.因此,在将它们提供给CustomerSyncEngine的模拟时不需要mockLogger.Object等,并且正如@JustinPihony所提到的,应该向您显示设计时错误. (2认同)
  • @GiriB 不需要,但可能,因为模拟是用 Params 定义的。公共模拟(参数对象[]参数) (2认同)
  • 我相信这个答案是不正确的。它应该是“varsyncEngine = new Mock&lt;CustomerSyncEngine&gt;(mockLogger.Object,mockCrm.Object,mockCache.Object).Object;”您应该将被模拟的对象传递给构造函数,而不是模拟本身。太长了;在模拟上使用“Object”属性。 (2认同)

Rag*_*ghu 31

最后一行是为您提供一个真实实例,因为您使用的是new关键字,而不是模拟CustomerSyncEngine.

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

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

最好的办法是右键单击您的班级并选择Extract interface.

  • 关于该问题,另一种方法是使用AutoMocking容器.我最喜欢的是Machine.Fakes与Machine.Specifications相结合,使用自动锁定容器可以更轻松地测试较小的表面区域.假设Andrew需要在`CustomerSyncEngine`中测试一个方法,该方法只使用`ICrmProvider`,必须为所有3个接口提供传统的模拟实现,而autmocking容器允许你只提供一个. (3认同)