tags:

views:

308

answers:

3

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.GetShippers()).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

A: 

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.

ryber
I've heard about IOC containers, but this would mean i have to set up concrete implementations of the interfaces...The only problem i see with using Concrete imp (be it Fake or in memory) is that it will become a maintenance nightmare. Especially when the number of test grows.
A: 

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;
Jeff Sternal
+5  A: 

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.

Ates Goral
+1. Additionally, complicated tests are often a sign that a single class is doing too much - especially when I see a name like "Controller" which seems awfully akin to "Manager." Look up the Inversion of Control principle... Additionally, try to make each logical action a single call to the object. So, instead of having multiple calls to Add, have a single one which can take a list.
kyoryu