开发者

TDD, Mocking, dependency injection and the DRY principle

I've got a controller class which accpets multiple parameters in the ctor which gets injected at runtime.

Example:

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

I am finding that the Test methods are getting huge. I am setting up the methods as follows:

[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.Ge开发者_如何学运维tShippers()).Returns(shippers);

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

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

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

Obviously, it not practical to repeat the mock setup in every method of this test class.

How can i create rich mocking objects that enables me to do Behavioural verification of my tests and at the same time minimise the setup pain?

What are the TDD best practices to deal with this problem?

Thanks


If your test framework supports setup/teardown functions that will be called before and after each test, create and destroy some "default" mock objects in those functions. Your tests can simply use those, and for special cases where the default mock objects don't work for you, you can simply ignore them and create local mock objects within those tests.


Use a Behavioural, or functional testing suite. Looks like your in C# or Java? Either way I would recommend FItnesse but there are others. As for the unit tests, I would probably use a IOC container like Winsor/Castle or Spring, then you can set up a container for the tests thats filled with Mocks rather than "real" objects.


I'd just extract this code into methods (if your mock framework requires you to pass the mock factory in, change the signature as needed):

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

Then, in your tests:

var mockProductRepository = SetupStandardMockProductRepository();

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜