我目前正在尝试对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.
我理解这一点,因为我是Moq的界面而且没有构造函数,但这也是我对单元测试和模拟的学习知识有点裸露的地方。
有人能告诉我如何正确地嘲笑这个测试吗?
答案 0 :(得分:1)
您的控制器依赖于存储库。最好将此依赖项显式化:
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();
}
答案 1 :(得分:1)
你的问题在这里(以及其他类似的行):
var mockRepositoryGenerator = new Mock<IRepositoryGenerator>();
var mockRepositorySelector = new Mock<IRepositorySelector>(mockRepositoryGenerator.Object);
正如您所说,您正在尝试创建一个IRepositorySelector模型,并将之前模拟的IRepositoryGenerator作为构造函数参数传递。但是Interfaces没有固有的构造函数,所以它不知道如何处理它。
您应该在接受IRepositoryGenerator的接口上公开一个属性(如果您还没有),然后在模拟接口后设置它:
var mockRepositoryGenerator = new Mock<IRepositoryGenerator>();
var mockRepositorySelector = new Mock<IRepositorySelector>();
mockRepositorySelector.Generator = mockRepositoryGenerator.Object;