Chuyển đến nội dung chính

Azure Functions: xUnit, Coverlet, và ReportGenerator - Day 6

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 là một loại kiểm thử phần mềm trong đó các đơn vị hoặc thành phần riêng lẻ của một phần mềm được kiểm tra. Mục đích là để xác nhận rằng mỗi đơn vị của mã phần mềm hoạt động như mong đợi.

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ị: 
  1. Unit Test giúp sửa lỗi sớm trong chu kỳ phát triển và tiết kiệm chi phí. 
  2. 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. 
  3. Unit Test được viết tốt có thể đóng vai trò như là tài liệu dự án. 
  4. 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ì?

Trong hướng đối tượng, mock object là đối tượng giả lập để mô tả, giả hành vi của đối tượng thật. Lập trình viên thường tạo ra các mock object để test các hành vi và chức năng của đối tượng khác.

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
Github: https://github.com/coverlet-coverage/coverlet

ReportGenerator là gì?

https://camo.githubusercontent.com/4aa9a044ca1b09a20425bf2aa3116ed22a9716359ff9336f4672df630d716c14/68747470733a2f2f64616e69656c70616c6d652e6769746875622e696f2f5265706f727447656e657261746f722f7265736f75726365732f696e7075745f6f75747075742e706e67ReportGenerator 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. 
Các báo cáo cho thấy tỷ lệ code coverage và cũng trực quan hóa những dòng mã nguồn nào đã được bao phủ. ReportGenerator có nhiều lợi ích và tính năng nổi bật như sau:
  • 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.Lib
public 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

UNIT TEST Là gì?

Unit tests with Moq in .NET 

https://github.com/danielpalme/ReportGenerator

TDD — 100% Code Coverage 

Nhận xét

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.