Create xUnit Test Project
Step 1:
Launch Visual Studio 2022 and Select “Create New Project”
Step 2:
Choose xUnit Test Project and press NEXT.
Step 3: Enter the Project name, and then click Create
Step 4: Select .NET 6 and press Create button. Your xUnit test project will be created.
Install NuGet Packages
1. Right click on the project and select Manage NuGet Package
2. Install the following plugins
- Moq
- Shouldy
Creating Relevant Folders
Step 1:
Right click on the project and Create a Folder named MockDatas . In this folder all the property class will be created. We are creating MockDatas for testing our projects function. Here i already a module named LoanOfficer. Our work is to test all the crud function inside the loan officer module.
Step 2:
Right click on the folder and create a class named LoanOfficerMockData and paste the following code in your class and change the property field according to yours.
using Products.Core.Entities; using System; using System.Collections.Generic; namespace Products.Test.MockDatas { public static class LoanOfficerMockData { public static List<LoanOfficer> loanofficerList = new List<LoanOfficer>(); public static List<LoanOfficer> updateloanofficerList = new List<LoanOfficer>(); public static List<LoanOfficer> deleteloanofficerList = new List<LoanOfficer>(); public static List<LoanOfficer> GetLoanOfficersData() { return loanofficerList; } public static List<LoanOfficer> updateGetLoanOfficersData() { return updateloanofficerList; } public static List<LoanOfficer> deleteGetLoanOfficersData() { return deleteloanofficerList; } public static void AddLoanOfficerStatic() { loanofficerList.Add(new LoanOfficer { Id = 1, Name = "Anik", Code = 001, Designation = "ASAI" }); loanofficerList.Add(new LoanOfficer { Id = 3, Name = "Ani", Code = 003, Designation = "ASAI" }); loanofficerList.Add(new LoanOfficer { Id = 2, Name = "Anik Saha", Code = 002, Designation = "ASAI" }); } public static void deleteAddLoanOfficerStatic() { deleteloanofficerList.Add(new LoanOfficer { Id = 1, Name = "Anik", Code = 001, Designation = "ASAI" }); deleteloanofficerList.Add(new LoanOfficer { Id = 3, Name = "Ani", Code = 003, Designation = "ASAI" }); deleteloanofficerList.Add(new LoanOfficer { Id = 2, Name = "Anik Saha", Code = 002, Designation = "ASAI" }); } public static void updateAddLoanOfficerStatic() { updateloanofficerList.Add(new LoanOfficer { Id = 1, Name = "Anik", Code = 001, Designation = "ASAI" }); updateloanofficerList.Add(new LoanOfficer { Id = 3, Name = "Ani", Code = 003, Designation = "ASAI" }); updateloanofficerList.Add(new LoanOfficer { Id = 2, Name = "Anik Saha", Code = 002, Designation = "ASAI" }); } public static void ResetLoanOfficerStatic() { loanofficerList.Clear(); } } }
Step 3:
Step 4:
using Moq; using Products.Application.Common.Interfaces.Repositories.Commands; using Products.Application.Common.Interfaces.Repositories.Queries; using Products.Core.Entities; using Products.Test.MockDatas; using System.Linq; namespace Products.Test.MockRepositories { public class MockLoanOfficerRepository { public MockLoanOfficerRepository() { LoanOfficerMockData.AddLoanOfficerStatic(); } public static Mock<ILoanOfficerQueryRepository> GetAllLoanOfficers() { var loanOfficers = LoanOfficerMockData.GetLoanOfficersData(); var mockRepo = new Mock<ILoanOfficerQueryRepository>(); mockRepo.Setup(x => x.GetAllLoanOfficers(1, 1)).ReturnsAsync(loanOfficers); return mockRepo; } public static Mock<ILoanOfficerQueryRepository> GetAllLoanOfficersByID() { var loanOfficer = LoanOfficerMockData.GetLoanOfficersData().Where(x => x.Id == 1).FirstOrDefault(); var mockRepo = new Mock<ILoanOfficerQueryRepository>(); mockRepo.Setup(x => x.GetLoanOfficerById(1)).ReturnsAsync(loanOfficer); return mockRepo; } public static Mock<ILoanOfficerQueryRepository> DeleteLoanOfficersByID() { var loanOfficer = LoanOfficerMockData.deleteGetLoanOfficersData().Where(x => x.Id == 1).FirstOrDefault(); var mockRepo = new Mock<ILoanOfficerQueryRepository>(); mockRepo.Setup(x => x.GetLoanOfficerById(1)).ReturnsAsync(loanOfficer); return mockRepo; } public static Mock<ILoanOfficerQueryRepository> UpdateLoanOfficersByID() { var loanOfficer = LoanOfficerMockData.updateGetLoanOfficersData().Where(x => x.Id == 1).FirstOrDefault(); var mockRepo = new Mock<ILoanOfficerQueryRepository>(); mockRepo.Setup(x => x.GetLoanOfficerById(1)).ReturnsAsync(loanOfficer); return mockRepo; } public static Mock<ILoanOfficerCommandRepository> CreateLoanOfficers() { var loanOfficers = LoanOfficerMockData.GetLoanOfficersData(); var mockRepoCreate = new Mock<ILoanOfficerCommandRepository>(); mockRepoCreate.Setup(r => r.CreateLoanOfficerAsync(It.IsAny<LoanOfficer>())).ReturnsAsync((LoanOfficer loanOfficer) => { LoanOfficerMockData.loanofficerList.Add(new LoanOfficer { }); return loanOfficer; }); return mockRepoCreate; } public static Mock<ILoanOfficerCommandRepository> DeleteLoanOfficer() { var loanOfficer = LoanOfficerMockData.GetLoanOfficersData().Where(x => x.Id == 1).FirstOrDefault(); var mockRepo = new Mock<ILoanOfficerCommandRepository>(); mockRepo.Setup(x => x.DeleteLoanOfficerAsync(loanOfficer)); return mockRepo; } public static Mock<ILoanOfficerCommandRepository> UpdateLoanOfficer() { var loanOfficer = LoanOfficerMockData.GetLoanOfficersData().Where(x => x.Id == 1).FirstOrDefault(); var mockRepo = new Mock<ILoanOfficerCommandRepository>(); mockRepo.Setup(x => x.UpdateLoanOfficerAsync(loanOfficer)); return mockRepo; } } }
Step 5:
Right click on the project and Create another Folder named Systems. Inside Systems folder, create a folder in your module name. In my case I have created a folder named LoanOfficer. Inside LoanOfficer folder create two folder named “Commands “ and “Queries”. In “Commands ” folder we will write test function for all Create, Edit and Delete and in “Queries” folder we will write test function for all List or Search functions.
Step 6:
Right click on the Queries folder and create a class GetLoanOfficerListRequestHandlerTests.cs and paste the following code in your class and change arrange, act and assert according to yours.
using AutoMapper; using Moq; using Products.Application.Common.Interfaces.Repositories.Queries; using Products.Application.Common.Mappings; using Products.Application.DTOs; using Products.Application.Queries.LoanOfficer; using Products.Test.MockDatas; using Products.Test.MockRepositories; using Shouldly; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Xunit; namespace Products.Test.Systems.LoanOfficer.Queries { public class GetLoanOfficerListRequestHandlerTests { private readonly IMapper _mapper; private readonly Mock<ILoanOfficerQueryRepository> _mockRepo, _mockRepoById; private readonly GetLoanOfficersQueryRequest _loanOfficerRequest; private readonly GetLoanOfficerByIdQueryRequest _loanOfficerIdRequest; public GetLoanOfficerListRequestHandlerTests() { LoanOfficerMockData.AddLoanOfficerStatic(); _mockRepo = MockLoanOfficerRepository.GetAllLoanOfficers(); _mockRepoById = MockLoanOfficerRepository.GetAllLoanOfficersByID(); var mapperConfig = new MapperConfiguration(c => { c.AddProfile<MappingProfile>(); }); _mapper = mapperConfig.CreateMapper(); _loanOfficerRequest = new GetLoanOfficersQueryRequest { Offset = 1, PageSize = 1, }; _loanOfficerIdRequest = new GetLoanOfficerByIdQueryRequest(1); } [Fact] public async Task GetLoanOfficerList() { ///arrange var handler = new GetLoanOfficerQueryRequestHandler(_mockRepo.Object, _mapper); ///act var result = await handler.Handle(_loanOfficerRequest, CancellationToken.None); ///assert result.ShouldBeOfType<List<LoanOfficerResponseDto>>(); result.Count().ShouldBe(3); } [Fact] public async Task GetLoanOfficerByID() { ///arrange var handler = new GetLoanOfficerByIdQueryRequestHandler(_mapper, _mockRepoById.Object); ///act var result = await handler.Handle(_loanOfficerIdRequest, CancellationToken.None); ///assert result.ShouldBeOfType<LoanOfficerResponseDto>(); result.Id.ShouldBe(1); } } }
Step 7:
Now go to Test Explorer. Here you can see your class name. Expand this and right click n your function and press run.
if your functions passes all the criteria it will return pass and returns green sign. Thogh your mockdata contains three records so list is pass if you write following in the assert option.
result.Count().ShouldBe(3);
Step 8:
Right click on the Commands folder and create a class named CreateLoanOfficerCommandHandlerTest.cs and paste the following code in your class and change arrange, act and assert according to yours.
using AutoMapper; using Moq; using Products.Application.Commands.LoanOfficer; using Products.Application.Common.Interfaces.Repositories; using Products.Application.Common.Interfaces.Repositories.Commands; using Products.Application.Common.Mappings; using Products.Application.DTOs; using Products.Test.MockDatas; using Products.Test.MockRepositories; using Shouldly; using System; using System.Linq; using System.Threading; using System.Threading.Tasks; using Xunit; namespace Products.Test.Systems.LoanOfficer.Commands { public class CreateLoanOfficerCommandHandlerTest { private readonly IMapper _mapper; private readonly Mock<ILoanOfficerCommandRepository> _mockRepo; private readonly IUnitOfWork _unitOfWork; private readonly CreateLoanOfficerCommandRequest _loanOfficerResponseDTO; public CreateLoanOfficerCommandHandlerTest() { _mockRepo = MockLoanOfficerRepository.CreateLoanOfficers(); var mapperConfig = new MapperConfiguration(c => { c.AddProfile<MappingProfile>(); }); _mapper = mapperConfig.CreateMapper(); var mockUoW = new Mock<IUnitOfWork>(); _unitOfWork = mockUoW.Object; _loanOfficerResponseDTO = new CreateLoanOfficerCommandRequest { Name = "ASAI", Code = 005, Designation = "SE" }; } [Fact] public async Task CreateLoanOfficer() { ///arrange var handler = new CreateLoanOfficerCommandRequestHandler(_mockRepo.Object, _mapper, _unitOfWork); ///act var result = await handler.Handle(_loanOfficerResponseDTO, CancellationToken.None); LoanOfficerMockData.ResetLoanOfficerStatic(); LoanOfficerMockData.AddLoanOfficerStatic(); LoanOfficerMockData.loanofficerList.Add(new Products.Core.Entities.LoanOfficer { Name = "ASAI", Code = 005, Designation = "SE" }); ///assert result.ShouldBeOfType<LoanOfficerResponseDto>(); LoanOfficerMockData.loanofficerList.Count().ShouldBe(4); } } }
Step 9:
Run test like previous. But this time your data count should be 4 cause it will add a new LoanOfficer in LoanOfficerMockData.
LoanOfficerMockData.loanofficerList.Count().ShouldBe(4);
Step 10:
Like this now create another class for Delete named DeleteLoanOfficerCommandHandlerTest.cs and paste the following code.
using AutoMapper; using Moq; using Products.Application.Commands.LoanOfficer; using Products.Application.Common.Interfaces.Repositories; using Products.Application.Common.Interfaces.Repositories.Commands; using Products.Application.Common.Interfaces.Repositories.Queries; using Products.Application.Common.Mappings; using Products.Test.MockDatas; using Products.Test.MockRepositories; using Shouldly; using System.Linq; using System.Threading; using System.Threading.Tasks; using Xunit; namespace Products.Test.Systems.LoanOfficer.Commands { public class DeleteLoanOfficerCommandHandlerTest { private readonly IUnitOfWork _unitOfWork; private readonly Mock<ILoanOfficerCommandRepository> _mockRepo; private readonly Mock<ILoanOfficerQueryRepository> _mockRepoList; private readonly DeleteLoanOfficerCommandRequest _loanOfficerDeleteRequest; public DeleteLoanOfficerCommandHandlerTest() { LoanOfficerMockData.AddLoanOfficerStatic(); _mockRepoList = MockLoanOfficerRepository.GetAllLoanOfficersByID(); _mockRepo = MockLoanOfficerRepository.CreateLoanOfficers(); LoanOfficerMockData.deleteAddLoanOfficerStatic(); _mockRepoList = MockLoanOfficerRepository.DeleteLoanOfficersByID(); _mockRepo = MockLoanOfficerRepository.DeleteLoanOfficer(); var mockUoW = new Mock<IUnitOfWork>(); _unitOfWork = mockUoW.Object; _loanOfficerDeleteRequest = new DeleteLoanOfficerCommandRequest(1); } [Fact] public async Task DeleteLoanOfficer() { ///arrange var handler = new DeleteLoanOfficerCommandRequestHandler(_mockRepoList.Object, _mockRepo.Object, _unitOfWork); ///act var result = await handler.Handle(_loanOfficerDeleteRequest, CancellationToken.None); var loanOfficer = LoanOfficerMockData.deleteGetLoanOfficersData().Where(x => x.Id == 1).FirstOrDefault(); LoanOfficerMockData.deleteloanofficerList.Remove(loanOfficer); ///assert result.ShouldBeOfType<int>(); LoanOfficerMockData.deleteloanofficerList.Count().ShouldBe(2); } } }
Step 11:
Run test like previous. But this time your data count should be 2 cause it will delete a LoanOfficer in LoanOfficerMockData.
LoanOfficerMockData.deleteloanofficerList.Count().ShouldBe(2);
Step 12:
Like this now create another class for Update named UpdateLoanOfficerCommandHandlerTest.cs and paste the following code.
using AutoMapper; using Moq; using Products.Application.Commands.LoanOfficer; using Products.Application.Common.Interfaces.Repositories; using Products.Application.Common.Interfaces.Repositories.Commands; using Products.Application.Common.Interfaces.Repositories.Queries; using Products.Application.Common.Mappings; using Products.Application.DTOs; using Products.Test.MockDatas; using Products.Test.MockRepositories; using Shouldly; using System.Linq; using System.Threading; using System.Threading.Tasks; using Xunit; namespace Products.Test.Systems.LoanOfficer.Commands { public class UpdateLoanOfficerCommandHandlerTest { private readonly IMapper _mapper; private readonly IUnitOfWork _unitOfWork; private readonly Mock<ILoanOfficerCommandRepository> _mockRepo; private readonly Mock<ILoanOfficerQueryRepository> _mockRepoList; private readonly UpdateLoanOfficerCommandRequest _loanOfficerUpdateRequest; public UpdateLoanOfficerCommandHandlerTest() { LoanOfficerMockData.updateAddLoanOfficerStatic(); _mockRepo = MockLoanOfficerRepository.UpdateLoanOfficer(); _mockRepoList = MockLoanOfficerRepository.UpdateLoanOfficersByID(); var mapperConfig = new MapperConfiguration(c => { c.AddProfile<MappingProfile>(); }); _mapper = mapperConfig.CreateMapper(); var mockUoW = new Mock<IUnitOfWork>(); _unitOfWork = mockUoW.Object; _loanOfficerUpdateRequest = new UpdateLoanOfficerCommandRequest { Id = 1, Name = "ASA International", Designation = "SE" }; } [Fact] public async Task UpdateLoanOfficer() { ///arrange var handler = new UpdateLoanOfficerCommandRequestHandler(_mapper, _mockRepo.Object, _mockRepoList.Object, _unitOfWork); ///act var result = await handler.Handle(_loanOfficerUpdateRequest, CancellationToken.None); var loanOfficer = LoanOfficerMockData.updateloanofficerList.FirstOrDefault(x => x.Id == 1); loanOfficer.Name = "ASA International"; ///assert result.ShouldBeOfType<LoanOfficerResponseDto>(); } } }
All Test cases are ready and go to GetLoanOfficerListRequestHandlerTests.cs class again and change result.Count().ShouldBe(4) in GetLoanOfficerList() function. Beacuse if we run all the test functions simultaniously, then CreateLoanOfficer() function will add a dataset. So GetLoanOfficerList() count should be 4 if we already have 3 dataset in MockLoanOfficerRepository.