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



问题背景:

我目前正在尝试对一个MVC4 WebApi项目进行单元测试。

该项目的结构使用了一个注入到相关控制器的构造函数中的facade类。这一切都是通过Unity实现的,以将紧密耦合保持在绝对最小。

即使考虑到Unity正在实现,在单元测试中,我也将产品控制器设置如下:

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

以下代码显示了控制器类的"GetProducts"方法:

public ProductController(IRepositoryFacade facade)
    {
        _facade = facade;
        productRepository = _facade.GetProductRepository();
    }
    public List<Product> GetProducts()
    {
        return productRepository.GetProducts();
    }

代码当前所在位置:

如果我只是想测试这个方法被击中的次数,我试着使用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();
    }

问题是:

目前,我在尝试设置测试中模拟对象的构造函数时遇到错误,如图所示:

Constructor arguments cannot be passed for interface mocks.

我理解这一点,因为我正在开发接口,并且没有构造函数,但这也是我学习单元测试和嘲笑知识的地方。

有人能告诉我如何正确地嘲笑这个测试吗?

您的控制器依赖于存储库。最好明确这种依赖关系:

public ProductController(IProductRepository productRepository)
{
    _productRepository = productRepository;
}
public List<Product> GetProducts()
{
    return _productRepository.GetProducts();
}

测试也变得容易多了:

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();
}

您的问题就在这里(以及其他类似的行):

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

正如您所说,您正试图创建一个模拟IRepositorySelector,并将之前模拟的IRepository Generator作为构造函数参数传入。但是接口没有固有的构造函数,所以它不知道该怎么处理它

您应该在接受IRepositoryGenerator的接口上公开一个属性(如果您还没有),然后在模拟接口后设置它:

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

最新更新