Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I unit test a method to add an item to a database?

I have an item and I am adding it to the database using this method:

public Messages addItem(Item item)
{

    Messages resultMessage = Messages.Success;

    using (IUnitOfWork unitOfWork = new UnitOfWork())
    {
        IItemRepository itemRep = new ItemRepository(unitOfWork);

        try
        {
            itemRep.Insert(item);

            unitOfWork.Commit();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.StackTrace);
            resultMessage = Messages.DB_Failure;
        }
    }    
    return resultMessage;   
}

Now I have to make write a unit test for this method to check if the item is being added to the database. I have no idea how I should do that, can someone help me?

like image 824
dtmnn Avatar asked May 21 '15 11:05

dtmnn


2 Answers

Your code is coupled with the ItemRepository and the UnitOfWork implementations. Ideally you should decouple them and use mocks to verify that the right methods are called.

A possible solution:

  1. Make the Repository a property on your unit of work
  2. Don't create the Unit of Work directly, use a factory for that
  3. Make the factory a dependency of your class
  4. In your test pass a mock of the factory to the class you are testing that returns a mock of the Unit Of Work
  5. Return a mock of the Repository on your UoW mock
  6. Verify that the right methods are called on your Repository mock and Unit of Work mocks

This would be an example. I have used Moq as the mocking framework. And put the test method inside the class, but you can get the idea:

class MyClass
{
    private readonly IUnitOfWorkFactory _factory;

    public MyClass(IUnitOfWorkFactory factory)
    {
        _factory = factory;
    }

    public Messages addItem(Item item)
    {
        Messages resultMessage = Messages.Success;

        using (IUnitOfWork unitOfWork = _factory.GetUnitOfWork())
        {
            try
            {
                unitOfWork.ItemRep.Insert(item);

                unitOfWork.Commit();
            }

            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
                resultMessage = Messages.DB_Failure;
            }


        }

        return resultMessage;
    }


    public void Test()
    {
        // Arrange
        var factoryMock = new Mock<IUnitOfWorkFactory>();
        var uowMock = new Mock<IUnitOfWork>();
        var repositoryMock = new Mock<IItemRepository>();

        factoryMock.Setup(f => f.GetUnitOfWork()).Returns(uowMock.Object);
        uowMock.Setup(u => u.ItemRep).Returns(repositoryMock.Object);

        var sut = new MyClass(factoryMock.Object);

        // Act
        var item = new Item();
        sut.addItem(item);


        // Assert
        repositoryMock.Verify(r => r.Insert(item), Times.Once);
        uowMock.Verify(u => u.Commit(), Times.Once);
    }
}
like image 67
Juan Avatar answered Oct 05 '22 11:10

Juan


You say that the goal is to "check if this item is added to the database".

This is something you do not normally write a unit test for because it is the responsibility of the database, which presumably you are not the one developing.

A better case for a unit test is to mock out the database and check the logic that decides to add something to the database. For instance:

  1. A Unit of Work is described by a customer/operator.
  2. Your component queries the database for the existence of the item.
  3. No corresponding item exists.
  4. Your component adds the item to the database.

This is achieved by using just a mock of the database and it is testing your code, rather than the database.

like image 34
Tormod Avatar answered Oct 05 '22 12:10

Tormod