Automated Testing: Integration Tests

Introduction

Unit testing help us to test, as the name says, a unit of funtionality. This unit is a method in a class that interacts only with attributes of the own class. In case that the class method interacts with another class that is provided externally, like a repository to an application service, then we are talking about integration testing.

Integration testing not only tests class interaction, also tests class interacting with external resources like databases, file storage or frameworks like Entity Framework.

1. Development Tools used in this post

The following tools I’ll be using in this post:

  • Visual Studio 2019 Community
  • NUnit 3
  • NUnit3TestAdapter
  • Moq

2. Creating the Project

First of all, open Visual Studio 2019 Community and search for Class Library type of project. In this case I’ll be using Class Library (.NET Framework) type of project.

type of project
Figure 2-1. Chosen type of project for integration testing with NUnit

Create three projects: one for Domain, one for Application Services and one for Integration Testing.

Figure 2-2. Projects contained in the solution

The sample domain that we’ll be unit testing is that of loan. Especifically, we’ll be testing interaction between repository and application service in the context of loan domain entity. Now let’s add the NUnit NuGet package to SampleApplicationServicesIntegrationTests project. Also we’ll be adding NUnit3TestAdapter in order to run tests in Visual Studio. Finally we have to add Moq in order to mock the application service dependencies.

Figure 2-3. NuGet packages installed for the integration testing project

3. Testing the Class Method

Now we have to declare a method in LoanAppServiceShould class. By convention it must be a phrase in english following the name of the class, particularly the “should” part. Integration testing has three parts:

  • Arrange: where initialization occurs.
  • Act: where execution of system under test occurs.
  • Assert: where assertions are verified.

Also we have to decorate the LoanAppServiceShould class with the TestFixture attribute of NUnit, as well as the method with the Test attribute. In the arrange part, all the neccesary objects are initialized. This include the repository as the dependency of the application service. In this case, the dependency is mocked. In the act part, the methods of the sut are executed and in the assert part, verifications are done. The code is as follows (note that “sut” is for system under test):

[TestFixture]
public class LoanAppServiceShould
{
    [Test]
    public void SaveLoanAndRetrieveSaved()
    {
        // Arrange
        Loan loan = new Loan() { OperationNumber = Guid.NewGuid() };

        Mock<ILoanRepository> loanRepositoryMock = new Mock<ILoanRepository>();

        loanRepositoryMock.Setup(r => r.Add(It.IsAny<Loan>()));

        loanRepositoryMock.Setup(r => r.GetById(It.Is<Guid>(p => p == loan.OperationNumber))).Returns(loan);

        ILoanAppService sut = new LoanAppService(loanRepositoryMock.Object);

        // Act
        sut.Add(loan);

        Loan loanAdded = sut.GetById(loan.OperationNumber);

        // Assert
        Assert.That(loan.OperationNumber == loanAdded.OperationNumber);

        loanRepositoryMock.Verify(r => r.Add(It.IsAny<Loan>()), Times.AtLeastOnce());

        loanRepositoryMock.Verify(r => r.GetById(loan.OperationNumber), Times.AtLeastOnce());
    }
}

Now it’s time to implement the designed code. In this case the methods LoanAppService::Add and LoanAppService::GetById. Following TDD, we have to implement a basic version of the methods in order to allow the test to fail. Then we refactor and the test will pass.

public class LoanAppService : ILoanAppService
{
    private readonly ILoanRepository loanRepository;

    public LoanAppService(ILoanRepository loanRepository)
    {
        this.loanRepository = loanRepository;
    }

    public void Add(Loan loan)
    {
        
    }

    public Loan GetById(Guid guid)
    {
        return new Loan();
    }
}
Figure 3-1. Failing integration test in the assertion of operation number equality

The refactored method looks like the following:

public class LoanAppService : ILoanAppService
{
    private readonly ILoanRepository loanRepository;

    public LoanAppService(ILoanRepository loanRepository)
    {
        this.loanRepository = loanRepository;
    }

    public void Add(Loan loan)
    {
        this.loanRepository.Add(loan);
    }

    public Loan GetById(Guid guid)
    {
        return this.loanRepository.GetById(guid);
    }
}

And the result of the test is that is passing

Figure 3-2. Passing integration test

Solution with source code files:

Conclusions

Integration testing is very useful to test interaction between classes and external resources like file storage or databases. They allow us to improve testability and modifiability with the confidence that our changes are not impacting negatively the system and the integration of components. Also, with the time, we accumulate tests so regression testing is easyly generated.

Your comments are important so we can share knowledge, ideas and thoughts about integration testing.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.