0

I'm trying to implement unit tests in my current project. After that I'll start developing using TDD further on in this project. Yesterday I started making some tests and it wasn't as easy as it looks in theory/books.

At the moment I'm struggling with a specific scenario, which I know someone else must have worked with in the past also.

Some background information. I've got a method called Add() in the class AddProduct. When a new object is passed to the Add method, there has to be made a new Item first, so I'll have to call the Add() method of the AddItem class first. All of this code exists in the Business Layer. Off-course the real adding happens in the DAL, which is called from within my AddProduct and AddItem classes.

To get an idea, this is what I have so far:

public class AddProduct : Product<IDataAccessAdd<Entities.Product>>, IBusinessAdd<Entities.Product>
{
    private readonly Business.IBusinessAdd<Entities.Item> _addItem;
    public AddProduct() : base(new DataAccess.AddProduct())
    {
        _addItem = new AddItem();
    }
        public AddProduct(DataAccess.IDataAccessAdd<Entities.Product> dal, Business.IBusinessAdd<Entities.Item> itemBl) : base(dal)
    {
        _addItem = itemBl;
    }

    private Entities.Product _newProduct;
    public bool Add(ref Product product, string user)
    {
        bool isAdded = false;
        _newProduct = product;
        if(AddNewItem(user))
        {
            isAdded = Dal.Add(product);
        }
        return isAdded;
    }

    private bool AddNewItem(string user)
    {
        var newItem = new Item();
        bool isAdded = _addItem.Add(ref newItem, user);
        _newProduct.Item = newItem;
        return isAdded;
    }
}

As you can see, I'm calling the AddNewItem from within the Add method.

The problem in this example is the constructor. I'd like to have a constructor with 0 or 1 parameter, like so:

public AddProduct() : base(new DataAccess.AddProduct())
{
}
public AddProduct(DataAccess.IDataAccessAdd<Entities.Product> dal) : base(dal)
{
}

and the AddNewItem method like so (or something similar):

private bool AddNewItem(string user)
{
    var newItem = new Item();
    var addItem = new Business.AddItem();
    bool isAdded = addItem.Add(ref newItem, user);
    _newProduct.Item = newItem;
    return isAdded;
}

But when doing this, the code executed in the AddNewItem method uses a 'real' DAL and I don't want that in a unit test. I solved this issue by adding a new parameter to the constructor, which can also create a mock DAL for the Business.Item class. However, I don't think this is the way to go. In theory, you could get a constructor with 20 parameters, all used for unit testing. Not a very pretty sight.

A colleague of mine told me this could probably be solved using a Factory Method design pattern, but he wasn't sure that would be a best choice. As I've never worked with the Factory Method design pattern, I don't feel very comfortable implementing it when unit testing is new to me also.

Any other suggestions which I could try?

Jan_V
  • 4,244
  • 1
  • 40
  • 64
  • 1
    Adding Unit Tests to existing code is always harder that starting from scratch. A useful book is 'Working Effectively with Legacy Code' (http://www.amazon.co.uk/Working-Effectively-Legacy-Robert-Martin/dp/0131177052/ref=sr_1_1?ie=UTF8&s=books&qid=1279700244&sr=8-1) which is all about adding unit tests to existing systems (although you wouldn't know from the title). – Dr Herbie Jul 21 '10 at 08:18
  • Thanks for the suggestion. As a matter of fact, I'm currently reading this specific book. It's quite good for learning how to approach certain cases. The book I read before this one was 'Clean Code', which is also a nice book if you want to start using unit tests (and better code). – Jan_V Jul 21 '10 at 09:24

1 Answers1

3

There's two approaches you can use here.

  1. Setup a IOC container specifically for testing. In this container you would configure the dal service to be your test or mock DAL service.

  2. Wire-up your classes manually. In this case you would explicitly call the AddProduct constructor and pass in your test or mock DAL service.

The rationale behind this is that dependency injection allows you to create a sandbox to isolate and test a specific part of your code. The options above create that sandbox.

Marnix van Valen
  • 13,265
  • 4
  • 47
  • 74
  • Hmm, an IoC Container looks pretty good, though camouflaging the problem if I understand it correct. This SO question: http://stackoverflow.com/questions/871405/why-do-i-need-an-ioc-container-as-opposed-to-straightforward-di-code And this page This link: http://timross.wordpress.com/2010/01/21/creating-a-simple-ioc-container/ Are really helpfull understanding it a bit better. – Jan_V Jul 21 '10 at 09:26