我有以下类,它使用构造函数注入:
public class Service : IService
{
public Service(IRepository repository, IProvider provider) { ... }
}
对于此类中的大多数方法,我只需为IRepository
和IProvider
创建Moq mock,并构造Service
。但是,类中有一个方法调用同一类中的其他几个方法。为了测试这个方法,我不想一起测试所有这些方法,而是想测试这个方法是否正确地调用了这些方法并正确地处理了它们的返回值。
最好的方法是模拟Service
。我以前曾毫无问题地嘲笑过Moq的具体课程。我甚至嘲笑过那些需要Moq构造函数参数的具体类。然而,这是我第一次需要将模拟参数传递到模拟对象的构造函数中。很自然,我试着这样做:
var repository = new Mock<IRepository>();
var provider = new Mock<IProvider>();
var service = new Mock<Service>(repository.Object, provider.Object);
然而,这是行不通的。相反,我得到了以下错误:
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: My.Namespace.Service.
Could not find a constructor that would match given arguments:
Castle.Proxies.IRepository
Castle.Proxies.IProvider
如果Service
的构造函数采用像int
s和string
s这样的简单参数,这就可以很好地工作,但如果它采用我正在嘲笑的接口,那就不行了。你是怎么做到的?
问题是您正在模拟您试图测试的服务。
如果您想要测试Service类的实现(无论是否是对模拟对象的调用),您所需要的只是两个接口的模拟,而不是测试类。
代替:
var repository = new Mock<IRepository>();
var provider = new Mock<IProvider>();
var service = new Mock<Service>(repository.Object, provider.Object);
应该是这样。
var repository = new Mock<IRepository>();
var provider = new Mock<IProvider>();
var service = new Service(repository.Object, provider.Object);
通常,模拟具体对象应该是最后的手段,但它不应该对测试的实际目标进行,因为这会产生副作用,即覆盖并向试图证明正确工作的类添加代码,从而可能使测试的目标完全无效。
我建议您不要模拟具体的对象,而是用模拟的依赖关系正常地实例化它。
当我的等价Service
有一个内部构造函数时,我遇到了一个非常类似的问题,所以Moq看不到它。
我添加了
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
到我的AssemblyInfo.cs文件中。不确定它是否相关,但我想补充一个建议,说明它对你或其他人有帮助的可能性。
这一定是旧版本的问题,最新版本都可以。尼克,请检查一下!
附言:我开始赏金是因为失误(我的建造师签名错误)。