简体   繁体   English

单元测试和Moq'ing构造函数参数问题

[英]Unit tests and Moq'ing constructor parameter issues

Question Background: 问题背景:

I'm currently trying to unit test an MVC4 WebApi project. 我目前正在尝试对MVC4 WebApi项目进行单元测试。

The structure of this project uses a facade class injected into the constructor of the relevant controller. 该项目的结构使用注入到相关控制器的构造函数中的facade类。 This is all achieved with Unity to keep close coupling to an absolute minimum. 这一切都是通过Unity实现的,以保持紧密耦合到绝对最小值。

Even thought Unity is being implemented, in the Unit tests I'm setting the product controllers up as follows: 即使认为Unity正在实施,在单元测试中我将产品控制器设置如下:

var repositoryFacade = new RepositoryFacade(new RepositorySelector(new RepositoryGenerator()));

var productController = new ProductController(repositoryFacade)

The following piece of code shows the 'GetProducts' method of the controller class: 下面的代码显示了控制器类的'GetProducts'方法:

public ProductController(IRepositoryFacade facade)
    {
        _facade = facade;

        productRepository = _facade.GetProductRepository();
    }

    public List<Product> GetProducts()
    {
        return productRepository.GetProducts();
    }

Where the code is currently at: 代码目前位于:

If I simply want to test how many times this method is hit, I tried setting my UnitTest up as follows, using the Moq framework: 如果我只想测试这个方法被击中的次数,我尝试使用Moq框架将我的UnitTest设置如下:

[TestMethod]
    public void Test_The_GetAllProducts_Method_is_Called()
    {

        var mockRepositoryGenerator = new Mock<IRepositoryGenerator>();

        var mockRepositorySelector = new Mock<IRepositorySelector>(mockRepositoryGenerator.Object);

        var mockFacade = new Mock<IRepositoryFacade>(mockRepositorySelector.Object);

        mockFacade.Setup(x => x.GetProductRepositoryV1().GetProducts());

        var productController = new ProductV1Controller(mockFacade.Object);

        var returnedProducts = productController.GetProducts();

        mockFacade.VerifyAll();
    }

The problem: 问题:

Currently I'm getting errors when trying to set the constructor of the mocked objects in the test, as shown: 目前,我在尝试在测试中设置模拟对象的构造函数时遇到错误,如下所示:

Constructor arguments cannot be passed for interface mocks.

I understand this as I'm Moq'ing the interface and there is no constructor, but this is also where my learning knowledge of Unit Tests and mocking is a bit bare. 我理解这一点,因为我是Moq'ing界面,没有构造函数,但这也是我对单元测试和模拟的学习知识有点裸露的地方。

Can anyone tell me how I would correctly go about mocking this test out? 谁能告诉我如何正确地嘲笑这个测试呢?

Your controller depends on repository. 您的控制器依赖于存储库。 It's better to make this dependency explicit: 最好将此依赖项显式化:

public ProductController(IProductRepository productRepository)
{
    _productRepository = productRepository;
}

public List<Product> GetProducts()
{
    return _productRepository.GetProducts();
}

Testing becomes much easier also: 测试变得更容易:

ProductV1Controller _productController;
Mock<IProductRepository> _mockRepository;

[TestInitialize]
public void TestInitialize()
{
    _mockRepository = new Mock<IProductRepository>();
    _productController = new ProductV1Controller(_mockRepository.Object);
}

[TestMethod]
public void ShouldLoadAllProducts()
{       
    _mockRepository.Setup(r => r.GetProducts()).Return(SomeProducts);

    var returnedProducts = _productController.GetProducts();

    Assert.Equals(returnedProducts, SomeProducts);
    _mockRepository.VerifyAll();
}

Your problem is here (and other lines like it): 你的问题在这里(以及其他类似的行):

var mockRepositoryGenerator = new Mock<IRepositoryGenerator>();

var mockRepositorySelector = new Mock<IRepositorySelector>(mockRepositoryGenerator.Object);

As you say, you are attempting to create a Mock of IRepositorySelector, and passing the previously mocked IRepositoryGenerator in as a constructor argument. 正如您所说,您正在尝试创建一个模拟IRepositorySelector,并将之前模拟的IRepositoryGenerator作为构造函数参数传递。 But Interfaces have no inherent constructors, so it doesn't know what to do with it. 但是Interfaces没有固有的构造函数,所以它不知道如何处理它。

You should expose a property on the interface that takes the IRepositoryGenerator (if you haven't got one already), then set it after you have mocked the interface: 您应该在接受IRepositoryGenerator的接口上公开一个属性(如果您还没有),然后在模拟接口后设置它:

var mockRepositoryGenerator = new Mock<IRepositoryGenerator>();

var mockRepositorySelector = new Mock<IRepositorySelector>();
mockRepositorySelector.Generator = mockRepositoryGenerator.Object;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM