繁体   English   中英

TDD,模拟,依赖项注入和DRY原理

[英]TDD, Mocking, dependency injection and the DRY principle

我有一个控制器类,它在ctor中支持多个参数,该ctor在运行时被注入。

例:

    public ProductController(IProductRepositort productRepository, 
IShippingService shippingService, IEmailProvider emailProvider)
    {
    ...
    }

我发现Test方法越来越庞大。 我正在设置以下方法:

[Test]
public void CanSendProduct()
{
    //Code to set up stub
                List<Product> products = new List<Product>();
                for (int i = 0; i < length; i++)
                {
                    products.Add(new Product()));
                }

                var mockProductRepository = new Mock<IProductRepository>();
                mockProductRepository.Setup(x => x.GetProducts()).Returns(products);

                //Code to set up stub
                ....
                ....   
                var mockShippingService = new Mock<IShippingService>();
                mockShippingService.Setup(x => x.GetShippers()).Returns(shippers);

                //Code to set up stub
                .....
                .....
                 var mockEmailProvider = new Mock<IEmailProvider>();
                mockEmailProvider.Setup(x => x.Send()).Returns(provider);

                //Execute Test
                ....
                ....

                //Assert
                ....
                ....
}

显然,在此测试类的每个方法中重复模拟设置都是不切实际的。

如何创建丰富的模拟对象,使我能够对测试进行行为验证,同时最大程度地减少设置麻烦?

解决此问题的TDD最佳做法是什么?

谢谢

如果您的测试框架支持在每次测试之前和之后都会调用的设置/拆卸功能,请在这些功能中创建并销毁一些“默认”模拟对象。 您的测试可以简单地使用那些,对于特殊情况,默认的模拟对象不适合您,您可以忽略它们并在这些测试中创建本地模拟对象。

使用行为或功能测试套件。 看起来像您在C#或Java中? 无论哪种方式,我都会推荐FItnesse,但还有其他方式。 至于单元测试,我可能会使用Winsor / Castle或Spring这样的IOC容器,然后可以为装有Mocks而不是“真实”对象的测试设置一个容器。

我只是将这些代码提取到方法中(如果您的模拟框架要求您传入模拟工厂,请根据需要更改签名):

private Mock<IProductRepository> SetupStandardMockProductRepository() {
    List<Product> products = new List<Product>();
    for (int i = 0; i < length; i++) {
        products.Add(new Product()));
    }    
    var mockProductRepository = new Mock<IProductRepository>();
    mockProductRepository.Setup(x => x.GetProducts()).Returns(products);
}

// ... and so forth

然后,在您的测试中:

var mockProductRepository = SetupStandardMockProductRepository();

// or make these static properties of some central test class, like this:
var mockProductRepository = Stubs.StandardProductRepository;

暂无
暂无

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

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