This document has multiple versions. Select the options best fit for you.

UI
Database

Web Application Development Tutorial - Part 4: Integration Tests

About This Tutorial

In this tutorial series, you will build an ABP based web application named Acme.BookStore. This application is used to manage a list of books and their authors. It is developed using the following technologies:

  • Entity Framework Core as the ORM provider.
  • MVC / Razor Pages as the UI Framework.

This tutorial is organized as the following parts;

Download the Source Code

This tutorial has multiple versions based on your UI and Database preferences. We've prepared a few combinations of the source code to be downloaded:

Video Tutorial

This part is also recorded as a video tutorial and published on YouTube.

Test Projects in the Solution

This part covers the server side tests. There are several test projects in the solution:

bookstore-test-projects-v2

Test projects slightly differs based on your UI and Database selection. For example, if you select MongoDB, then the Acme.BookStore.EntityFrameworkCore.Tests will be Acme.BookStore.MongoDB.Tests.

Each project is used to test the related project. Test projects use the following libraries for testing:

The test projects are configured to use SQLite in-memory as the database. A separate database instance is created and seeded (with the data seed system) to prepare a fresh database for every test.

Adding Test Data

If you had created a data seed contributor as described in the first part, the same data will be available in your tests. So, you can skip this section. If you haven't created the seed contributor, you can use the BookStoreTestDataSeedContributor to seed the same data to be used in the tests below.

Testing the BookAppService

Add a new test class, named BookAppService_Tests in the Books namespace (folder) of the Acme.BookStore.Application.Tests project:

using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Xunit;

namespace Acme.BookStore.Books
{ 
    public class BookAppService_Tests : BookStoreApplicationTestBase
    {
        private readonly IBookAppService _bookAppService;

        public BookAppService_Tests()
        {
            _bookAppService = GetRequiredService<IBookAppService>();
        }

        [Fact]
        public async Task Should_Get_List_Of_Books()
        {
            //Act
            var result = await _bookAppService.GetListAsync(
                new PagedAndSortedResultRequestDto()
            );

            //Assert
            result.TotalCount.ShouldBeGreaterThan(0);
            result.Items.ShouldContain(b => b.Name == "1984");
        }
    }
}
  • Should_Get_List_Of_Books test simply uses BookAppService.GetListAsync method to get and check the list of books.
  • We can safely check the book "1984" by its name, because we know that this books is available in the database since we've added it in the seed data.

Add a new test method to the BookAppService_Tests class that creates a new valid book:

[Fact]
public async Task Should_Create_A_Valid_Book()
{
    //Act
    var result = await _bookAppService.CreateAsync(
        new CreateUpdateBookDto
        {
            Name = "New test book 42",
            Price = 10,
            PublishDate = System.DateTime.Now,
            Type = BookType.ScienceFiction
        }
    );

    //Assert
    result.Id.ShouldNotBe(Guid.Empty);
    result.Name.ShouldBe("New test book 42");
}

Add a new test that tries to create an invalid book and fails:

[Fact]
public async Task Should_Not_Create_A_Book_Without_Name()
{
    var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
    {
        await _bookAppService.CreateAsync(
            new CreateUpdateBookDto
            {
                Name = "",
                Price = 10,
                PublishDate = DateTime.Now,
                Type = BookType.ScienceFiction
            }
        );
    });

    exception.ValidationErrors
        .ShouldContain(err => err.MemberNames.Any(mem => mem == "Name"));
}
  • Since the Name is empty, ABP will throw an AbpValidationException.

The final test class should be as shown below:

using System;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Validation;
using Xunit;

namespace Acme.BookStore.Books
{ 
    public class BookAppService_Tests : BookStoreApplicationTestBase
    {
        private readonly IBookAppService _bookAppService;

        public BookAppService_Tests()
        {
            _bookAppService = GetRequiredService<IBookAppService>();
        }

        [Fact]
        public async Task Should_Get_List_Of_Books()
        {
            //Act
            var result = await _bookAppService.GetListAsync(
                new PagedAndSortedResultRequestDto()
            );

            //Assert
            result.TotalCount.ShouldBeGreaterThan(0);
            result.Items.ShouldContain(b => b.Name == "1984");
        }
        
        [Fact]
        public async Task Should_Create_A_Valid_Book()
        {
            //Act
            var result = await _bookAppService.CreateAsync(
                new CreateUpdateBookDto
                {
                    Name = "New test book 42",
                    Price = 10,
                    PublishDate = System.DateTime.Now,
                    Type = BookType.ScienceFiction
                }
            );

            //Assert
            result.Id.ShouldNotBe(Guid.Empty);
            result.Name.ShouldBe("New test book 42");
        }
        
        [Fact]
        public async Task Should_Not_Create_A_Book_Without_Name()
        {
            var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
            {
                await _bookAppService.CreateAsync(
                    new CreateUpdateBookDto
                    {
                        Name = "",
                        Price = 10,
                        PublishDate = DateTime.Now,
                        Type = BookType.ScienceFiction
                    }
                );
            });

            exception.ValidationErrors
                .ShouldContain(err => err.MemberNames.Any(mem => mem == "Name"));
        }
    }
}

Open the Test Explorer Window (use Test -> Windows -> Test Explorer menu if it is not visible) and Run All tests:

bookstore-appservice-tests

Congratulations, the green icons indicates that the tests have been successfully passed!

The Next Part

See the next part of this tutorial.

In this document