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 two 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

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:

  1. using System.Threading.Tasks;
  2. using Shouldly;
  3. using Volo.Abp.Application.Dtos;
  4. using Xunit;
  5. namespace Acme.BookStore.Books
  6. {
  7. public class BookAppService_Tests : BookStoreApplicationTestBase
  8. {
  9. private readonly IBookAppService _bookAppService;
  10. public BookAppService_Tests()
  11. {
  12. _bookAppService = GetRequiredService<IBookAppService>();
  13. }
  14. [Fact]
  15. public async Task Should_Get_List_Of_Books()
  16. {
  17. //Act
  18. var result = await _bookAppService.GetListAsync(
  19. new PagedAndSortedResultRequestDto()
  20. );
  21. //Assert
  22. result.TotalCount.ShouldBeGreaterThan(0);
  23. result.Items.ShouldContain(b => b.Name == "1984");
  24. }
  25. }
  26. }
  • 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:

  1. [Fact]
  2. public async Task Should_Create_A_Valid_Book()
  3. {
  4. //Act
  5. var result = await _bookAppService.CreateAsync(
  6. new CreateUpdateBookDto
  7. {
  8. Name = "New test book 42",
  9. Price = 10,
  10. PublishDate = System.DateTime.Now,
  11. Type = BookType.ScienceFiction
  12. }
  13. );
  14. //Assert
  15. result.Id.ShouldNotBe(Guid.Empty);
  16. result.Name.ShouldBe("New test book 42");
  17. }

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

  1. [Fact]
  2. public async Task Should_Not_Create_A_Book_Without_Name()
  3. {
  4. var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
  5. {
  6. await _bookAppService.CreateAsync(
  7. new CreateUpdateBookDto
  8. {
  9. Name = "",
  10. Price = 10,
  11. PublishDate = DateTime.Now,
  12. Type = BookType.ScienceFiction
  13. }
  14. );
  15. });
  16. exception.ValidationErrors
  17. .ShouldContain(err => err.MemberNames.Any(mem => mem == "Name"));
  18. }
  • Since the Name is empty, ABP will throw an AbpValidationException.

The final test class should be as shown below:

  1. using System;
  2. using System.Linq;
  3. using System.Threading.Tasks;
  4. using Shouldly;
  5. using Volo.Abp.Application.Dtos;
  6. using Volo.Abp.Validation;
  7. using Xunit;
  8. namespace Acme.BookStore.Books
  9. {
  10. public class BookAppService_Tests : BookStoreApplicationTestBase
  11. {
  12. private readonly IBookAppService _bookAppService;
  13. public BookAppService_Tests()
  14. {
  15. _bookAppService = GetRequiredService<IBookAppService>();
  16. }
  17. [Fact]
  18. public async Task Should_Get_List_Of_Books()
  19. {
  20. //Act
  21. var result = await _bookAppService.GetListAsync(
  22. new PagedAndSortedResultRequestDto()
  23. );
  24. //Assert
  25. result.TotalCount.ShouldBeGreaterThan(0);
  26. result.Items.ShouldContain(b => b.Name == "1984");
  27. }
  28. [Fact]
  29. public async Task Should_Create_A_Valid_Book()
  30. {
  31. //Act
  32. var result = await _bookAppService.CreateAsync(
  33. new CreateUpdateBookDto
  34. {
  35. Name = "New test book 42",
  36. Price = 10,
  37. PublishDate = System.DateTime.Now,
  38. Type = BookType.ScienceFiction
  39. }
  40. );
  41. //Assert
  42. result.Id.ShouldNotBe(Guid.Empty);
  43. result.Name.ShouldBe("New test book 42");
  44. }
  45. [Fact]
  46. public async Task Should_Not_Create_A_Book_Without_Name()
  47. {
  48. var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
  49. {
  50. await _bookAppService.CreateAsync(
  51. new CreateUpdateBookDto
  52. {
  53. Name = "",
  54. Price = 10,
  55. PublishDate = DateTime.Now,
  56. Type = BookType.ScienceFiction
  57. }
  58. );
  59. });
  60. exception.ValidationErrors
  61. .ShouldContain(err => err.MemberNames.Any(mem => mem == "Name"));
  62. }
  63. }
  64. }

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.