在使用Moq模拟具体类时,如何使用接口参数调用构造函数

时间:2014-04-18 14:47:25

标签: class mocking moq constructor-injection concreteclass

我有以下类,它使用构造函数注入:

public class Service : IService
{
    public Service(IRepository repository, IProvider provider) { ... }
}

对于本课程中的大多数方法,我只需为IRepositoryIProvider创建Moq模拟并构造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的构造函数采用intstring s这样的简单参数,这样可以正常工作,但如果它采用我嘲笑的接口则不行。你是怎么做到的?

3 个答案:

答案 0 :(得分:6)

你为什么嘲笑你正在测试的服务?如果您希望测试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);

我意识到在某些框架中模拟具体对象是可能的,但你的目的是什么?模拟某些东西背后的想法是删除实际的实现,以便它不会影响您的测试。但是在您的问题中,您已声明您希望知道正确调用某些类,然后您希望验证这些操作的结果。这无疑是对实施的测试,因此,我很难看到嘲笑具体对象的目标。

答案 1 :(得分:5)

当我的等效Service有一个内部构造函数时,我遇到了一个非常类似的问题,因此Moq看不到它。

我添加了

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

到我的AssemblyInfo.cs文件中的实现项目。不确定它是否相关,但我想补充一个关于它有助于你或其他人的机会的建议。

答案 2 :(得分:1)

必须是旧版本问题,最新版本都可以。尼克,请检查!

P.s。:我通过错误开始赏金(我的构造函数中有错误的签名)。