Web应用程序开发教程 - 第四章: 集成测试

关于本教程

在本系列教程中, 你将构建一个名为 Acme.BookStore 的用于管理书籍及其作者列表的基于ABP的应用程序. 它是使用以下技术开发的:

  • Entity Framework Core 做为ORM提供程序.
  • MVC / Razor Pages 做为UI框架.

本教程分为以下部分:

下载源码

本教程根据你的UI数据库偏好有多个版本,我们准备了几种可供下载的源码组合:

如果你在Windows中遇到 “文件名太长” or “解压错误”, 很可能与Windows最大文件路径限制有关. Windows文件路径的最大长度为250字符. 为了解决这个问题,参阅 在Windows 10中启用长路径.

如果你遇到与Git相关的长路径错误, 尝试使用下面的命令在Windows中启用长路径. 参阅 https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path git config --system core.longpaths true

视频教程

本章也被录制为视频教程 发布在YouTube.

解决方案中的测试项目

这一部分涵盖了 服务器端 测试. 解决方案中有多个测试项目:

bookstore-test-projects-v2

根据你选择的UI和数据库, 测试项目略微有所不同. 例如, 如果选择MongoDB, 那么 Acme.BookStore.EntityFrameworkCore.Tests 会变为 Acme.BookStore.MongoDB.Tests.

每个项目用于测试相关的应用程序项目.测试项目使用以下库进行测试:

测试项目配置为使用 SQLite内存 作为数据库. 创建一个单独的数据库实例并使用数据种子系统初始化种子数据,为每个测试准备一个新的数据库.

添加测试数据

如果你已经按照第一部分中的描述创建了数据种子贡献者,则相同的数据也在测试中可用. 因此你可以跳过此部分. 如果你尚未创建种子贡献者,可以使用 BookStoreTestDataSeedContributor 来为要在以下测试中使用的相同数据提供种子.

测试 BookAppService

Acme.BookStore.Application.Tests 项目的 Books 命名空间(文件夹)中创建一个名叫 BookAppService_Tests 的测试类:

  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. }
  29. }
  • 测试方法 Should_Get_List_Of_Books 直接使用 BookAppService.GetListAsync 方法来获取用户列表,并执行检查.
  • 我们可以安全地检查 “1984” 这本书的名称,因为我们知道这本书可以在数据库中找到,我们已将其添加到种子数据中.

新增测试方法,用以测试创建一个合法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 = 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. }

新增测试方法,用以测试创建一个非法book实体失败的场景:

  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. }
  • 由于 Name 是空值, ABP 抛出一个 AbpValidationException 异常.

最终的测试类如下所示:

  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 = 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. }

打开测试资源管理器(测试 -> Windows -> 测试资源管理器)并执行所有测试:

bookstore-appservice-tests

恭喜你, 绿色图标表示测试已成功通过!

下一章

查看本教程的下一章.