dtmnn
dtmnn

Reputation: 243

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?

Upvotes: 6

Views: 14599

Answers (4)

Tormod
Tormod

Reputation: 4583

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.

Upvotes: 1

Juan
Juan

Reputation: 3705

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);
    }
}

Upvotes: 7

prgmtc
prgmtc

Reputation: 750

As other answers suggested: try to separate your class under test from difficult/slow to test dependencies like the database. You can use a number of approaches to achieve this result, but they all come down to the same: Don't create (new up) dependencies that make unit testing difficult in the code you want to test itself (like your unitofwork/repository). Rather, ask these dependencies from the outside world (google Dependency Inversion/DI for further info).

If you want to test the implementation of the repository with a real database, I suggest you test through the public API of your repository. Don't go writing "SELECT * FROM Items" queries yourself, but use a repository.GetItem(...) method if available. That way your tests are less brittle and decoupled from the actual implementation of your repository class.

Upvotes: 0

David Arno
David Arno

Reputation: 43264

As your method currently stands, it cannot be unit tested as it's hard-coded to write to the database.

The conventional way around this is to pass an instance of IItemRepository into the method, rather than having the method create it. Do that and then you are free to create a mocked IItemRepository implementation that can report what's being written to the DB.

Upvotes: 0

Related Questions