diff --git a/docs/en/Testing.md b/docs/en/Testing.md index fe005756ca..624af8ee24 100644 --- a/docs/en/Testing.md +++ b/docs/en/Testing.md @@ -36,7 +36,7 @@ There are more than one test project, organized by the layers; * `Domain.Tests` is used to test your Domain Layer objects (like [Domain Services](Domain-Services.md) and [Entities](Entities.md)). * `Application.Tests` is used to test your Application Layer (like [Application Services](Application-Services.md)). -* `EntityFrameworkCore.Tests` is used to test your custom repository implementations or EF Core mappings (this project will be different if you use another [Database Provider](Data-Access.md)). +* `EntityFrameworkCore.Tests` is used to implement abstract test classes and test your custom repository implementations or EF Core mappings (this project will be different if you use another [Database Provider](Data-Access.md)). * `Web.Tests` is used to test the UI Layer (like Pages, Controllers and View Components). This project does exists only for MVC / Razor Page applications. * `TestBase` contains some classes those are shared/used by the other projects. @@ -537,12 +537,13 @@ using Xunit; namespace MyProject.Issues { - public class IssueManager_Integration_Tests : MyProjectDomainTestBase + public abstract class IssueManager_Integration_Tests : MyProjectDomainTestBase + where TStartupModule : IAbpModule { private readonly IssueManager _issueManager; private readonly Issue _issue; - public IssueManager_Integration_Tests() + protected IssueManager_Integration_Tests() { _issueManager = GetRequiredService(); _issue = new Issue @@ -577,6 +578,8 @@ namespace MyProject.Issues } ```` +> The `IssueManager_Integration_Tests` class is abstract, See the **Implementing unit tests in EF Core and MongoDB** section below. + * First test method assigns the issue to the User 1, which has already assigned to 3 issues in the Data Seed code. So, it throws a `BusinessException`. * Second test method assigns the issue to User 2, which has only 1 issue assigned. So, the method succeeds. @@ -625,11 +628,12 @@ using Xunit; namespace MyProject.Issues { - public class IssueAppService_Tests : MyProjectApplicationTestBase + public abstract class IssueAppService_Tests : MyProjectApplicationTestBase + where TStartupModule : IAbpModule { private readonly IIssueAppService _issueAppService; - public IssueAppService_Tests() + protected IssueAppService_Tests() { _issueAppService = GetRequiredService(); } @@ -647,6 +651,8 @@ namespace MyProject.Issues } ```` +> The `IssueAppService_Tests` class is abstract, See the **Implementing unit tests in EF Core and MongoDB** section below. + It's that simple. This test method tests everything, including the application service, EF Core mapping, object to object mapping and the repository implementation. In this way, you can fully test the Application Layer and the Domain Layer of your solution. ### Dealing with Unit of Work in Integration Tests @@ -658,11 +664,12 @@ In the ABP Framework, all the database operations must be performed inside a uni In some cases, you may need to manually control the unit of work scope. Consider the following test method: ````csharp -public class IssueRepository_Tests : MyProjectDomainTestBase +public abstract class IssueRepository_Tests : MyProjectDomainTestBase + where TStartupModule : IAbpModule { private readonly IRepository _issueRepository; - public IssueRepository_Tests() + protected IssueRepository_Tests() { _issueRepository = GetRequiredService>(); } @@ -676,17 +683,20 @@ public class IssueRepository_Tests : MyProjectDomainTestBase } ```` +> The `IssueRepository_Tests` class is abstract, See the **Implementing unit tests in EF Core and MongoDB** section below. + We are using `_issueRepository.GetQueryableAsync` to obtain an `IQueryable` object. Then, we are using the `FirstOrDefaultAsync` method to query an issue by its title. The database query is executed at this point, and you get an exception indicating that there is no active unit of work. To make that test properly working, you should manually start a unit of work scope as shown in the following example: ````csharp -public class IssueRepository_Tests : MyProjectDomainTestBase +public abstract class IssueRepository_Tests : MyProjectDomainTestBase + where TStartupModule : IAbpModule { private readonly IRepository _issueRepository; private readonly IUnitOfWorkManager _unitOfWorkManager; - public IssueRepository_Tests() + protected IssueRepository_Tests() { _issueRepository = GetRequiredService>(); _unitOfWorkManager = GetRequiredService(); @@ -716,12 +726,13 @@ In some cases, you may want to directory work with the Entity Framework's `DbCon The following example shows how you can create a `DbContext` object in a test method: ````csharp -public class MyDbContext_Tests : MyProjectDomainTestBase +public abstract class MyDbContext_Tests : MyProjectDomainTestBase + where TStartupModule : IAbpModule { private readonly IDbContextProvider _dbContextProvider; private readonly IUnitOfWorkManager _unitOfWorkManager; - public IssueRepository_Tests() + protected IssueRepository_Tests() { _dbContextProvider = GetRequiredService>(); _unitOfWorkManager = GetRequiredService(); @@ -740,10 +751,29 @@ public class MyDbContext_Tests : MyProjectDomainTestBase } ```` +> The `MyDbContext_Tests` class is abstract, See the **Implementing unit tests in EF Core and MongoDB** section below. + Just like we've done in the *Dealing with Unit of Work in Integration Tests* section, we should perform `DbContext` operations inside an active unit of work. For [MongoDB](MongoDB.md), you can use the `IMongoDbContextProvider` service to obtain a `DbContext` object and directly use MongoDB APIs in your test methods. +## Implementing unit tests in EF Core and MongoDB + +The unit test classes in `.Domain.Test` and `.Application.Tests` above are abstract classes, We need to implement the test classes in EF Core or MongoDB test projects to run the tests. + +A example implementation for the `IssueManager_Integration_Tests` class in the `.EntityFrameworkCore.Tests` project is shown below: + +````csharp +namespace MyProject.EntityFrameworkCore.Applications; + +public class EfCoreIssueAppService_Tests : IssueAppService_Tests +{ + +} +```` + +![unitest-efcore-mongodb](images/unitest-efcore-mongodb.png) + ## UI Tests In general, there are two types of UI Tests; diff --git a/docs/en/images/solution-test-projects.png b/docs/en/images/solution-test-projects.png index e51c368e9f..87ac41c6a1 100644 Binary files a/docs/en/images/solution-test-projects.png and b/docs/en/images/solution-test-projects.png differ diff --git a/docs/en/images/unitest-efcore-mongodb.png b/docs/en/images/unitest-efcore-mongodb.png new file mode 100644 index 0000000000..4145d9d7c9 Binary files /dev/null and b/docs/en/images/unitest-efcore-mongodb.png differ diff --git a/docs/en/images/vs-run-tests-in-parallel.png b/docs/en/images/vs-run-tests-in-parallel.png index 765cba5100..cb33bd76c2 100644 Binary files a/docs/en/images/vs-run-tests-in-parallel.png and b/docs/en/images/vs-run-tests-in-parallel.png differ diff --git a/docs/en/images/vs-startup-template-tests.png b/docs/en/images/vs-startup-template-tests.png index f16d79a4c7..0e45200e13 100644 Binary files a/docs/en/images/vs-startup-template-tests.png and b/docs/en/images/vs-startup-template-tests.png differ