Table Of Content
Giới thiệu
Unit Testing là một phần quan trọng trong quá trình phát triển phần mềm để đảm bảo chất lượng code và giảm thiểu bug. Trong ASP.NET Core, Unit Testing giúp kiểm tra các đơn vị nhỏ nhất của ứng dụng (hàm, method, class) một cách độc lập.
Mục tiêu của Unit Testing
- Kiểm tra logic từng phần nhỏ của ứng dụng mà không phụ thuộc vào các thành phần khác.
Lợi ích
- Giúp phát hiện lỗi sớm trong quá trình phát triển.
- Tăng độ tin cậy của phần mềm.
- Hỗ trợ bảo trì và mở rộng code dễ dàng.
- Thúc đẩy phát triển theo TDD (Test-Driven Development).
- Nâng cao khả năng refactor code mà không sợ phá vỡ logic hiện có.
Unit Testing trong ASP.NET Core
Cài đặt môi trường
Cài đặt các thư viện cần thiết:
dotnet add package xUnit
dotnet add package Moq
dotnet add package FluentAssertions
dotnet add package AutoFixture
dotnet add package Microsoft.NET.Test.Sdk
dotnet add package Coverlet.MSBuild
AAA Pattern (Arrange – Act – Assert)
AAA Pattern là một phương pháp tổ chức kiểm thử giúp code test rõ ràng, dễ hiểu:
- Arrange: Thiết lập đối tượng, dữ liệu đầu vào, và môi trường kiểm thử.
- Act: Gọi phương thức hoặc logic cần kiểm tra.
- Assert: Kiểm tra kết quả đầu ra có đúng với mong đợi không.
Ví dụ:
[Fact]
public void Add_ShouldReturnSum_WhenTwoNumbersArePassed()
{
// Arrange
var service = new CalculatorService();
// Act
var result = service.Add(2, 3);
// Assert
result.Should().Be(5);
}
Viết Unit Test cơ bản
Giả sử có CalculatorService
với phương thức Add
:
public class CalculatorService
{
public int Add(int a, int b) => a + b;
public int Subtract(int a, int b) => a - b;
public int Multiply(int a, int b) => a * b;
public int Divide(int a, int b) => b == 0 ? throw new DivideByZeroException() : a / b;
}
Viết Unit Test sử dụng xUnit
và FluentAssertions
:
using Xunit;
using FluentAssertions;
public class CalculatorServiceTests
{
private readonly CalculatorService _service = new();
[Fact]
public void Subtract_ShouldReturnDifference_WhenTwoNumbersArePassed()
{
var result = _service.Subtract(5, 3);
result.Should().Be(2);
}
[Fact]
public void Multiply_ShouldReturnProduct_WhenTwoNumbersArePassed()
{
var result = _service.Multiply(4, 3);
result.Should().Be(12);
}
[Fact]
public void Divide_ShouldThrowException_WhenDividingByZero()
{
var act = () => _service.Divide(10, 0);
act.Should().Throw<DivideByZeroException>();
}
}
Unit Test với Mocking (Moq)
Mocking là gì?
Mocking là kỹ thuật tạo ra các đối tượng giả lập thay thế cho phụ thuộc bên ngoài như database, API, hoặc service khác. Điều này giúp cô lập logic cần kiểm tra mà không phụ thuộc vào trạng thái hoặc phản hồi thực từ bên ngoài.
Lợi ích của Moq trong Unit Testing
- Giúp kiểm tra code mà không cần phụ thuộc vào cơ sở dữ liệu thật.
- Tăng tốc độ kiểm thử do không có kết nối thật với hệ thống bên ngoài.
- Kiểm thử các luồng xử lý ngoại lệ dễ dàng hơn.
- Đảm bảo rằng chỉ các phương thức mong đợi được gọi.
Giả sử có repository:
public interface IUserRepository
{
Task<User> GetUserByIdAsync(int id);
Task<IEnumerable<User>> GetAllUsersAsync();
Task<bool> DeleteUserAsync(int id);
}
Service sử dụng repository:
public class UserService
{
private readonly IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public async Task<string> GetUserName(int id)
{
var user = await _userRepository.GetUserByIdAsync(id);
return user?.Name ?? "Unknown";
}
}
Test Service với Moq:
using Moq;
using System.Threading.Tasks;
using Xunit;
using FluentAssertions;
public class UserServiceTests
{
private readonly Mock<IUserRepository> _mockRepo;
private readonly UserService _userService;
public UserServiceTests()
{
_mockRepo = new Mock<IUserRepository>();
_userService = new UserService(_mockRepo.Object);
}
[Fact]
public async Task GetUserName_ShouldReturnUserName_WhenUserExists()
{
_mockRepo.Setup(r => r.GetUserByIdAsync(1))
.ReturnsAsync(new User { Id = 1, Name = "John Doe" });
var result = await _userService.GetUserName(1);
result.Should().Be("John Doe");
}
}
Best Practices trong Unit Testing
- Sử dụng AAA Pattern để đảm bảo test rõ ràng và dễ hiểu.
- Không test những thứ không cần thiết (tránh mock quá nhiều thành phần không quan trọng).
- Dùng
FluentAssertions
thay vìAssert.Equal
để dễ đọc hơn. - Test theo Black Box thay vì kiểm tra logic nội bộ.
- Ưu tiên kiểm thử logic quan trọng hơn là test những phần phụ trợ.
- Sử dụng AutoFixture để tạo dữ liệu test nhanh chóng.
- Dùng Code Coverage để đo lường phạm vi kiểm thử.
- Mock đúng phạm vi, không lạm dụng để tránh test không phản ánh đúng hệ thống thật.
- Chạy test tự động trong CI/CD pipelines để đảm bảo chất lượng liên tục.
Kết Luận
- Unit Test giúp kiểm tra logic chi tiết và ổn định.
- Mocking giúp cô lập code test mà không cần kết nối hệ thống bên ngoài.
- Sử dụng FluentAssertions và AutoFixture giúp code test dễ đọc, dễ viết.
- Viết test cho tất cả các logic quan trọng để đảm bảo hệ thống ổn định.
- Áp dụng best practices giúp giảm thiểu lỗi và tối ưu hóa quy trình phát triển.
Bằng cách sử dụng Unit Testing đúng cách, bạn có thể xây dựng hệ thống ASP.NET Core có chất lượng cao, đáng tin cậy và dễ mở rộng.
No Comment! Be the first one.