Hôm nay mình sẽ giới thiệu về hai công cụ hữu ích cho việc kiểm thử phần mềm .NET: xUnit và ReportGenerator. Các bạn có thể sử dụng hai công cụ này để viết các test case, chạy các test case và tạo báo cáo code coverage cho các dự án của mình.
Nội dung bao gồm:
- Unit Test là gì?
- Moq Object là gì?
- Code coverage là gì?
- Moq là gì?
- xUnit là gì?
- ReportGenerator là gì?
- Cách cài đặt và sử dụng xUnit và ReportGenerator trong Visual Studio.
- Cách tạo báo cáo code coverage với ReportGenerator và xem kết quả trên trình duyệt.
Unit Test là gì?
Unit Test được thực hiện bởi các nhà phát triển trong quá trình phát triển (giai đoạn viết code) của một ứng dụng. Unit Test cô lập một đơn vị code và xác minh tính đúng đắn của nó. Một đơn vị có thể là một function, method, mô-đun hoặc đối tượng riêng lẻ.
Các bạn có thể tham khảo bài viết so sánh các công cụ Unit Test trong .NET: Comparison Of Unit Testing Tools In .NET
Tại sao nên sử dụng Unit Test?
Unit Test là rất quan trọng bởi vì các nhà phát triển phần mềm đôi khi cố gắng tiết kiệm thời gian bằng cách thực hiện các kiểm thử tối thiểu.Đây là nguyên nhân dẫn đến chi phí sửa lỗi cao trong quá trình kiểm tra hệ thống, kiểm tra tích hợp và thậm chí thử nghiệm Beta sau khi ứng dụng được xây dựng.
Nếu Unit Test được thực hiện sớm trong quá trình phát triển phần mềm, thì cuối cùng nó sẽ giúp tiết kiệm thời gian và tiền bạc.
Dưới đây là những lý do chính để thực hiện kiểm thử đơn vị:
- Unit Test giúp sửa lỗi sớm trong chu kỳ phát triển và tiết kiệm chi phí.
- Nó giúp các nhà phát triển hiểu rõ code và cho phép họ thực hiện các thay đổi nhanh chóng.
- Unit Test được viết tốt có thể đóng vai trò như là tài liệu dự án.
- Unit Test giúp tái sử dụng lại mã dễ dàng. Di chuyển cả code và unit test của bạn sang dự án mới của bạn. Chỉnh sửa mã cho đến khi các bài kiểm tra chạy lại.
Moq Object là gì?
Github: https://github.com/moq/moq4
Code Coverage là gì?
Code Coverage là một thuật ngữ trong lĩnh vực kiểm thử phần mềm, có nghĩa là độ phủ của các dòng code đã được chạy qua các test case mà chúng ta đã viết. Code Coverage giúp chúng ta đánh giá chất lượng của mã nguồn và đảm bảo ít bug nhất xảy ra. Code Coverage có thể được tính trên những thành phần như lines (dòng code), functions & methods (các hàm và các phương thức), classes & traits
Tại sao Code Coverage quan trọng
Code Coverage quan trọng vì nó giúp đánh giá chất lượng và hiệu quả của mã nguồn và các trường hợp kiểm thử. Code Coverage cho biết mức độ mã nguồn được thực thi trong quá trình kiểm thử và xác định các lỗ hổng, lỗi hoặc mã chết. Code Coverage cũng giúp ngăn ngừa rò rỉ lỗi, kiểm tra hồi quy, ưu tiên trường hợp kiểm thử và tối ưu hóa bộ kiểm thử. Code Coverage là một chỉ số quan trọng trong kiểm thử phần mềm về chất lượng và hiệu quả.
xUnit là gì?
xUnit là một framework kiểm thử đơn vị (unit testing) cho các ứng dụng .NET. xUnit được phát triển bởi các nhà phát triển có kinh nghiệm trong việc tạo ra các framework kiểm thử khác như NUnit hay MSTest. xUnit có nhiều lợi ích và tính năng nổi bật như sau:- xUnit hỗ trợ nhiều loại test case khác nhau, như Fact, Theory, InlineData, ClassData, MemberData, v.v. Mỗi loại test case có một cách viết và chạy khác nhau, phù hợp với các trường hợp cụ thể.
- xUnit hỗ trợ viết các test case theo phong cách BDD (Behavior Driven Development) với Given-When-Then. Điều này giúp cho các test case dễ đọc và hiểu hơn, cũng như thể hiện rõ ràng hành vi mong đợi của mã nguồn.
- xUnit hỗ trợ chạy song song (parallel) các test case để tăng tốc độ kiểm thử. Bạn có thể điều chỉnh số lượng test case chạy song song bằng cách sử dụng thuộc tính MaxParallelThreads hoặc Parallelizable.
- xUnit hỗ trợ sử dụng các thuộc tính (attribute) để điều khiển quá trình kiểm thử, như Skip, Trait, BeforeAfterTestAttribute, CollectionAttribute, v.v. Bạn có thể sử dụng các thuộc tính này để bỏ qua, phân loại, thiết lập hoặc dọn dẹp các test case theo ý muốn.
- xUnit hỗ trợ tích hợp với các công cụ khác như Visual Studio Test Explorer, ReSharper, CodeRush, TestDriven.NET, v.v. Bạn có thể sử dụng các công cụ này để viết, chạy và debug các test case một cách dễ dàng.
Coverlet là gì?
Coverlet là một công cụ mã nguồn mở trên GitHub, giúp tạo báo cáo code coverage cho các ứng dụng .NET. Coverlet có thể tích hợp với các framework unit test phổ biến như xUnit, NUnit, MSTest và các công cụ khác như Visual Studio, ReportGenerator, Azure DevOps, GitHub Actions, v.v. Coverlet có thể xuất ra các file báo cáo ở nhiều định dạng khác nhau như json, lcov, opencover, cobertura, v.v.
Một số tools khác:
- OpenCover
- dotCover
ReportGenerator là gì?
ReportGenerator là một công cụ dòng lệnh mã nguồn mở trên GitHub, giúp chuyển đổi các báo cáo code coverage được tạo bởi coverlet, OpenCover, dotCover, Visual Studio, NCover, Cobertura, JaCoCo, Clover, gcov hoặc lcov thành các báo cáo dễ đọc ở nhiều định dạng khác nhau.- ReportGenerator hỗ trợ nhiều định dạng báo cáo khác nhau, như HTML, HTMLSummary, XML, JSON, Latex, v.v. Bạn có thể chọn định dạng phù hợp với nhu cầu của mình hoặc sử dụng nhiều định dạng cùng lúc.
- ReportGenerator hỗ trợ gộp nhiều file code coverage thành một báo cáo duy nhất. Bạn có thể sử dụng tính năng này để kết hợp các báo cáo từ nhiều máy tính, nhiều phiên bản, nhiều framework hoặc nhiều ngôn ngữ khác nhau.
- ReportGenerator hỗ trợ tạo báo cáo lịch sử (history report), tức là báo cáo về sự thay đổi của code coverage qua các phiên bản. Bạn có thể sử dụng tính năng này để theo dõi tiến độ và chất lượng của mã nguồn theo thời gian.
- ReportGenerator hỗ trợ tùy biến báo cáo theo nhiều cách khác nhau, như thay đổi tiêu đề, thẻ, bộ lọc, v.v. Bạn có thể sử dụng các tùy chọn dòng lệnh hoặc viết các plugin riêng để tùy biến báo cáo theo ý muốn.
Thực hành
Trong Visual Studio, tạo 2 project: Calculator.Lib (Class Library) và MoqSample (xUnit Test Project)
Tạo interface ICalculator trong project Calculator.Libpublic interface ICalculator
{
decimal Add(decimal num1, decimal num2);
decimal Substract(decimal num1, decimal num2);
decimal Multiply(decimal num1, decimal num2);
decimal Divide(decimal num1, decimal num2);
Task<int> AddTwoNumbersAsync(int a, int b);
}
Tạo class FakeCalculator
public class FakeCalculator : ICalculator
{
public decimal Add(decimal num1, decimal num2)
{
return num1 + num2;
}
public decimal Divide(decimal num1, decimal num2)
{
throw new NotImplementedException();
}
public virtual decimal Multiply(decimal num1, decimal num2)
{
throw new NotImplementedException();
}
public decimal Substract(decimal num1, decimal num2)
{
throw new NotImplementedException();
}
// Define an async method that takes two integers as parameters and returns their sum as a Task<int>
public async Task<int> AddTwoNumbersAsync(int a, int b)
{
// Use await to asynchronously wait for the result of adding the two numbers
int result = await Task.Run(() => a + b);
// Return the result
return result;
}
}
Mở Project Test, bạn sẽ thấy đoạn coverlet. Bạn không cần phải install coverlet từ dòng lệnh
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Tạo Code Coverage
Thêm file Unit Test for interface ICalculator
public class UnitTest1
{
[Fact]
public void PassingTest()
{
var calculator = new FakeCalculator();
Assert.Equal(4, calculator.Add(2, 2));
}
[Fact]
public void Real_FakeCalculator_Multiply_Not_Implemented_Method_Test()
{
var calculator = new Mock<FakeCalculator>();
calculator.Setup(x => x.Multiply(2, 3)).Returns(6);
Assert.Equal(6, calculator.Object.Multiply(2, 3));
}
[Fact]
public void Real_FakeCalculator_Moq()
{
var calculator = new Mock<FakeCalculator>();
calculator.Setup(x => x.Multiply(2, 3)).Returns((decimal a, decimal b) => a);
Assert.Equal(2, calculator.Object.Multiply(2, 3));
}
[Fact]
public async Task Real_FakeCalculator_Moq_Async()
{
Func<int, int, Task<int>> addAsync = async (a, b) =>
{
// Use await to asynchronously wait for the result of adding the two integers
int result = await Task.Run(() => a + b);
// Return the result
return result;
};
var calculator = new Mock<ICalculator>();
calculator.Setup(x => x.AddTwoNumbersAsync(2, 3)).ReturnsAsync((int a, int b) => 5);
Assert.Equal(5, await calculator.Object.AddTwoNumbersAsync(2, 3));
}
}
Để chạy các test case, bạn có thể sử dụng Visual Studio Test Explorer hoặc dùng lệnh dotnet test trong Package Manager Console hoặc Terminal.
dotnet tool install --global coverlet.console
Để tạo báo cáo code coverage, bạn chạy câu lệnh sau ở đường dẫn chứa file project Test
dotnet test --collect:"XPlat Code Coverage"
XPlat Code Coverage được sử dụng để thu thập dữ liệu về code coverage của các Unit Test trong .NET
Sau khi chạy lệnh này, bạn sẽ thấy kết quả code coverage trên console và một file coverage.cobertura.xml được tạo ra trong thư mục TestResults. File này chứa các thông tin về code coverage nhưng không dễ đọc cho con người. Bạn có thể sử dụng công cụ ReportGenerator để chuyển đổi file này thành một file HTML dễ đọc hơn.
Sử dụng ReportGenerator để tạo báo cáo HTML
Bạn có thể cài đặt ReportGenerator vào dự án test của bạn bằng cách sử dụng Package Manager Console hoặc Manage NuGet Packages for Solution trong Visual Studio.
dotnet add package ReportGenerator
Chạy câu lệnh sau để tạo report
reportgenerator -reports:"TestResults\**\coverage.cobertura.xml" -targetdir:"coveragereport" -reporttypes:Html
Sau khi chạy lệnh này, bạn sẽ thấy một file index.htm được tạo ra trong thư mục coveragereport. File này là file HTML chứa báo cáo code coverage của mã nguồn. Bạn có thể mở file này bằng trình duyệt để xem kết quả code coverage. Bạn sẽ thấy tỷ lệ code coverage và cũng có thể xem từng dòng mã nguồn đã được bao phủ hay không.
Kết luận
Trong bài viết này, mình đã hướng dẫn các bạn cách sử dụng xUnit, Coverlet, và ReportGenerator .
xUnit không tạo ra code coverage mà chỉ là một framework để viết và chạy các test case. Để tạo ra code coverage, bạn cần sử dụng một công cụ khác như coverlet, một framework mã nguồn mở cho C# có thể tích hợp với xUnit. Coverlet sẽ thu thập dữ liệu code coverage khi bạn chạy các test case với xUnit và xuất ra các file báo cáo ở nhiều định dạng khác nhau.
Sau đó bạn dùng ReportGenerator để chuyển đổi các file báo cáo của coverlet thành các báo cáo dễ đọc hơn
Tham khảo
Create a complete Azure Function project in .NET 5 using VSCode
https://www.telerik.com/blogs/unit-testing-linq-to-sql
Nhận xét
Đăng nhận xét