开发者

Unit test method with mock DAL, but underlying method calls different (real) DAL

开发者 https://www.devze.com 2023-01-08 17:35 出处:网络
I\'m trying to implement unit tests in my current project. After that I\'ll start developing using TDD further on in this project.

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 AddPro开发者_如何学Goduct 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?


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.

0

精彩评论

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