Anton P
Anton P

Reputation:

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.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

Upvotes: 2

Views: 1050

Answers (3)

Ateş G&#246;ral
Ateş G&#246;ral

Reputation: 140182

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.

Upvotes: 6

Jeff Sternal
Jeff Sternal

Reputation: 48675

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;

Upvotes: 0

ryber
ryber

Reputation: 4555

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.

Upvotes: 0

Related Questions