Xu Hướng 3/2023 # Viết Unit Test Trong C# Với Nunit # Top 6 View | Ezlearning.edu.vn

Xu Hướng 3/2023 # Viết Unit Test Trong C# Với Nunit # Top 6 View

Bạn đang xem bài viết Viết Unit Test Trong C# Với Nunit được cập nhật mới nhất trên website Ezlearning.edu.vn. Hy vọng những thông tin mà chúng tôi đã chia sẻ là hữu ích với bạn. Nếu nội dung hay, ý nghĩa bạn hãy chia sẻ với bạn bè của mình và luôn theo dõi, ủng hộ chúng tôi để cập nhật những thông tin mới nhất.

Ở trường đại học chắc các bạn đã được học khái niệm về Unit Test trong môn “Kiểm thử chất lượng phần mềm”. Nói một cách dễ hiểu, unit test tức là code dùng để test code ta đã viết.

Một số đặc điểm của unit test:

Code unit test phải ngắn gọn, dễ hiểu, dễ đọc.

Mỗi unit test là 1 đơn vi riêng biệt, độc lập, không phụ thuộc vào unit khác.

Mỗi unit test là 1 method trong test class, tên method cũng là tên UnitTest. Do đó ta nên đặt tên hàm rõ ràng, nói rõ unit test này test cái gì (Test_A_Do_B), tên method có thể rất dàiii cũng không sao.

Unit Test phải nhanh, vì nó sẽ được chạy để kiểm định lỗi mỗi lần build. Do đó trong unit test nên hạn chế các task tốn thời gian như gọi I/O, database, network,…

Unit Test nên test từng đối tượng riêng biệt. Vd: Unit Test cho Business Class thì chỉnh test chính BusinessClass đó, không nên dụng tới các class móc nối với nó (DataAccess Class chẳng hạn).

Một số bạn sẽ thắc mắc: “Ơ hay, trong business class thì phải gọi data access chứ?”, và “code mình dính chùm lắm, làm sao test từng class riêng được”.

Để viết unit test, các class của bạn phải có quan hệ “lõng lẽo” với nhau (loose coupling), nếu không viết được unit test nghĩa là các class dính với nhau quá chặt, sẽ khó thay đổi sau này. Hãy áp dụng các nguyên lý SOLID vào code, viết code với tư tưởng “viết sao để unit test được” sẽ là code của bạn uyển chuyển, dễ test hơn.

Về vấn đề Business Class và Data Access, các class không nên gọi trực tiếp lẫn nhau mà gọi thông qua interface. Khi unit test, ta sẽ thay các hiện thực interface này bằng các class giả, thay thế cho class data access thật. Mình sẽ nói rõ về vấn đề này ở những bài viết về Inversion of Control, Dependency Injection trong tương lai.

Một số lợi ích của Unit Test:

Nếu viết Unit Test một cách cẩn thận, code của bạn sẽ ít lỗi hơi, vì Unit Test sẽ phát hiện lỗi cho bạn.

Phát hiện những hàm chạy chậm và không hiệu quả thông qua thời gian chạy của Unit Test.

Tăng sự tự tin khi code, vì đã có Unit Test phát hiện lỗi.

Khi refactor code, sửa code hay thêm chức năng mới, Unit Test đảm bảo chương trình chạy đúng, phát hiện những lỗi tiềm tàng mà ta bỏ lỡ.

Unit Test trong C# với NUnit

Trước đây, để viết Unit Test trong C#, ta thường phải tạo một project test riêng, sử dụng thư viện MSTest của Microsoft. MSTest hỗ trợ khá nhiều chức năng: Test dữ liệu từ database, đo performance hệ thống, xuất dữ liệu report. Tuy nhiên, do MSTest đi kèm với Visual Studio, không thể chạy riêng rẽ, lại khá nặng nề, do đó NUnit được nhiều người ưa thích hơn. NUnit có 1 bộ runner riêng, có thể chạy UnitTest độc lập không cần VisualStudio, ngoài ra nó cũng hỗ trợ một số tính năng mà MSTest không có (parameter test, Assert Throw).

Nếu bạn chưa bao giờ viết Unit Test, bắt đầu với NUnit cũng là 1 lựa chọn không tồi. Đầu tiên, ta hãy tạo 1 project console trong Visual Studio. Ta viết 1 class Calculator với các 2 hàm Add và Subtract:

public class Calculator { public int Add(int x, int y) { return x + y; } public int Subtract(int x, int y) { return x - y; } } using NUnit.Framework; [TestFixture] public class CalculatorTest { private Calculator _cal; [SetUp] public void Setup() { _cal = new Calculator(); } [Test] public void OnePlusOneEqualTwo() { Assert.AreEqual(2, _cal.Add(1, 1)); } [Test] public void TwoPlusTwoEqualFour() { Assert.AreEqual(4, _cal.Add(2, 2)); } [Test] public void FourPlusOneEqualFive() { Assert.AreEqual(5, _cal.Add(4, 1)); } }

Giải thích một số annotation:

Annotation [TextFixture] đặt vào đầu class chứa các unit test, đánh dấu đây là một bộ các unit test.

Annotation [SetUp] để đánh dấu hàm setup. Hàm này sẽ được chạy vào đầu mỗi unit test.

Để chạy Unit Test, ta cần cài NUnit.TestAdapter, đây là bộ runner cho phép chạy các Unit Test của NUnit trong Visual Studio. Bạn cũng có thể dùng 1 trong 2 cách sau:

Tải NUnit GuiRunner về, mở file dll của project test, các unit test sẽ hiện ra để chạy.

Tải Reshaper. Reshaper cũng tích hợp sẵn 1 bộ Runner cho phép chạy Unit Test của NUnit.

Ta cố ý sửa lại code để code chạy sai. Chạy lại Unit Test, ta sẽ thấy các case đã fail. Unit Test đã tự động bắt lỗi chương trình cho bạn rồi đấy. Bấm vào từng test case, ta sẽ thấy kết quả mong muốn ở đoạn ” Excepted“, kết quả code chạy ở đoạn ” But was “.

Viết Unit Test Cho Javascript Với Jasmine

Blog có khá nhiều bài về code rồi nên hôm nay mình sẽ viết một bài để đổi gió.

1. Nhắc lại sơ về Unit Test

Trước khi có unit test, các lập trình viên thường code theo kiểu: code – test – fix lại – code tiếp – test lại – fix tiếp. Đôi khi chỉ vì sửa 1 lỗi nho nhỏ mà ta phải test lại rất nhiều lần. Để giải quyết vấn đề này, unit test và automation test ra đời. Mình không phải QA chuyên nghiệp nên không dám múa rìu qua mắt thợ, chỉ nói sơ về định nghĩa của 2 loại test này:

Unit test: Đây là test do developer viết, được chạy để kiểm tra các hàm do developer viết ra có sai hay ko. Unit test thường được chạy mỗi khi build để đảm bảo các hàm đều chạy đúng sau khi ta sửa code.

Automation test: Đây là test do QA viết, được chạy để kiểm thử hệ thống (Nếu không có automation test thì QA kiểm thử bằng tay, gọi làm manual test).

Bài viết này chỉ tập trung vào unit test. Đây là test mà developer chúng ta phải viết. Các thư viện thường dùng để viết unit test là jUnit (Java), nUnit (C#), thư viện test của Microsoft, … Một số khái niệm cần biết trong unit test:

Setup: Đây là hàm được chạy trước khi chạy các test case, thường dùng để khai báo dữ liệu, cài đặt các biến.

Teardown: Đây là hàm được chạy sau khi các test case chạy xong, thường dùng để xóa dữ liệu, giải phóng bộ nhớ.

Assert: Mỗi test case sẽ có 1 hoặc nhiều câu lệnh Assert, để kiểm tra tính đúng đắn của hàm. Vd: Assert.Equals(4, Add(2,2));

Mock: Giả sử chương trình của bạn được chia làm 2 module: A và B. Module A đã code xong, B thì chưa. Để test module A, ta dùng mock để làm giả module B, không cần phải đợi tới khi module B code xong mới test được.

2. Giới thiệu về Jasmine

3. Demo Jasmine

Để đơn giản, chúng ta sẽ tạo 1 file spec mới làm ví dụ, đặt tên là chúng tôi Ta sửa lại file html như sau:

function Calculator() { chúng tôi = function(a, b) { return a+b;}; this.minus = function(a, b) { return a-b;}; this.multiply = function(a, b) { return a*b;}; this.divide = function(a,b) {return a/b;} ; }

Một số unit test cộng trừ nhân chia

Hàm describe dùng để gom nhóm, ghi chú cho nhiều unit test.

Hàm it tương đương với 1 unit test.

Hàm expect chính là hàm assert để kiểm tra tính đúng đắn của unit test

describe("Cộng trừ", function() { var cal = new Calculator(); it("Một với một là hai", function() { expect(2).toBe(cal.add(1,1)); }); it("Hai với hai là bốn", function() { expect(4).toBe(cal.add(2,2)); }); it("Năm trừ hai bằng ba", function() { expect(3).toBe(cal.minus(5,2)); }); }); describe("Nhân chia", function() { var cal = new Calculator(); it("Năm nhân hai bằng mười", function() { expect(10).toBe(cal.multiply(5,2)); }); it("Sáu chia hai bằng ba", function() { expect(3).toBe(cal.divide(6,2)); }); });

Chạy lại file SpecRunner.html, ta được kết quả. Giả sử ta cố ý sửa lại cho hàm minus chạy sai, ta sẽ thấy unit test báo hàm sai như sau: Bài viết tới đây là kết thúc. Ở phần 2, mình sẽ hướng dẫn chi tiết hơn về cách dùng hàm setup, teardown và mock với Jasmine. Các bạn có thể tải code sample của bài viết này ở đây: https://github.com/conanak99/jasmine-sample.

Tìm Hiểu Unit Testing Trongcore

Tìm hiểu Unit Testing trong chúng tôi Core

Unit test là gì?

Unit test đơn giản giúp chúng ta kiểm tra tính đúng đắn của một đơn vị code (hầu hết là các method) có làm việc như mong muốn không? Nó cho phép bạn kiểm tra các phương thức độc lập và kiểm tra các logic với các điều kiện dữ liệu khác nhau.

Tại sao phải dùng Unit test?

Một lý do lớn là unit test giúp dễ dàng thay đổi code hơn nhiều khi chúng ta chắc rằng chúng ta không thay đổi tính năng (refactoring) mà chỉ là tối ưu code thôi. Điều này có nghĩa là unit test giúp bạn có thể dễ dàng phát hiện ra những chỗ bị lỗi khi thay đổi code nhờ các test case báo fail ở bất kỳ function nào. Điều này rất tuyệt vời bởi vì các bug bị giảm đi rất nhiều trong ứng dụng của chúng ta ngay từ các đơn vị code nhỏ nhất. Bug càng phát hiện sớm càng giảm chi phí cho việc fix.

Unit test làm cho thiết kế tốt hơn

Unit test giúp ảnh hưởng đến thiết kế của chúng ta bằng cách luôn theo xu hướng giảm sự phụ thuộc giữa các module đến mức cao nhất. Nếu một số chỗ không thể test được thì tức là có sự phụ thuộc không hề nhẹ ở đây tức là thiết kế chưa được tối ưu cho việc test cũng như bảo trì (tightly coupled). Khi chúng ta thiết kế các class với unit test trong tư duy bạn sẽ tập trung vào việc tách ra các thành phần độc lập và có thể test được.

Trong một số trường hợp, bạn thường không phải nghĩ về thiết kế. Các unit test sẽ hướng dẫn bạn chắc chắn rằng các logic là đúng và các thành phần được thiết kế tách biệt và giảm sự phụ thuộc thông qua việc sử dụng các abstraction và dependency injection. Điều này có được nếu như chúng ta thiết kế tuân theo Single Reponsibility Principle (nguyên tắc S trong SOLID).

Tìm hiểu về test-driven development

Mình thường viết code ngắn và sau đó viết lên dần dần song song với việc viết các unit test và thực hành như vậy tôi gọi là tư duy hướng test (test driven thinking). Test-driven development (TDD) là một quy trình khác khi mà các test được viết trước cả khi viết code. Các test như là các đặc tả (spec) mà bạn phải viết test khi function chưa được hình thành. Ban đầu test sẽ fail vì chưa có code tồn tại. Sau đó bạn chỉ cần viết code để cho các test case đó pass.

Trong khi TDD thường hướng tới unit testing, unit testing thì lại không yêu cầu phải làm TDD. Tôi muốn các bạn rõ điều này vì nó hơi bị dễ nhầm lẫn giữa các term này.

Thêm unit test vào project

Một cách tiếp cận tốt để unit test trong .NET là thêm các test vào solution của chúng ta dưới dạng class library hoàn toàn tách biệt với các project code chính. Giờ chúng ta sẽ thêm mới một .NET Core Class library vào solution như hình.

Tiếp đến là thêm một unit test framework, mình sử dụng xUnit được hỗ trợ cho .NET core và làm việc với tính năng có sẵn trong Visual Studio là Test Runner. Nunit cũng là một framework phổ biến khác, có một số khác nhau giữa 2 thằng này nhưng tựu chung là nó gần như nhau.

Thêm các thư viện bổ sung để mock tức là giả lập các đối tượng với các logic khác nhau và dữ liệu khác nhau trong unit test. Điều này có thể tham khảo tại bài viết này về mock, stubbing và faking đối tượng ở đây. Chúng ta sẽ dành 1 phút để sử dụng thư viện Moq để giả lập các hành vi của một interface trong test case, đây là tính năng rất mạnh mẽ của unit test.

Cuối cùng chúng ta cần Add reference từ project test đến project code chính để truy cập các class cho việc test.

Viết unit test

Ok vậy chúng ta đã hiểu một số lý thuyết rồi, bao gồm có việc hiểu khái niệm unit test, tại sao phải dùng chúng. Chúng ta sẽ test ứng dụng với xUnit framework.

Test đầu tiên chúng ta sẽ sử dụng class TeamStatCalculator. Cụ thể là method GetTotalGoalsForSeason()

public class TeamStatCalculator { private readonly ITeamStatRepository _teamStatRepository; public TeamStatCalculator(ITeamStatRepository teamStatRepository) { _teamStatRepository = teamStatRepository; } public int GetTotalGoalsForSeason(int seasonId) { var teamStatsBySeason = _teamStatRepository } }

Cả nhà thấy nó giống với cách viết của project TEDU-17 không? Đi vào chi tiết chúng ta có thể thấy phương thức này đơn giản là query từ _teamStatRepository và lấy ra danh sách các đội bóng theo mùa sau đó gọi hàm Sum() trong Linq để trả ra tổng bàn thắng cho toàn bộ. Quá dễ phải không nào?

Một điều ghi nhớ là chúng ta có thể thấy _teamStatRepository là một thành phần phụ thuộc được inject vào thông qua constructor. Trong thực tế, repository này có thể lấy dữ liệu từ database, một file hoặc một Rest API nào đó nhưng chúng ta không cần quan tâm vì chúng ta ủy thác việc lấy dữ liệu từ nguồn nào cho phần triển khai của IteamStatRepository interface. Chúng ta chỉ quan tâm là với một interface trừu tượng như thế nó có các phương thức trừu tượng và không dính gì đến phần triển khai. Chúng ta sẽ thấy vì sao điều này rất quan trọng ngay sau đây. Thêm nữa, nếu code test của bạn viết vào 1 file, mở database lên thông qua connection hoặc làm gì đó thông qua network thì nó sẽ thành test tích hợp mất (integration test) rồi. Cái này là phạm trù khác của test.

[Fact] public void GetTotalGoalsForSeason_returns_expected_goal_count() { var mockTeamStatRepo = new Mock(); mockTeamStatRepo { new TeamStatSummary {SeasonId = 1,Team = "team 1",GoalsFor=1}, new TeamStatSummary {SeasonId=1,Team = "team 2",GoalsFor=2}, new TeamStatSummary {SeasonId = 1,Team = "team 3",GoalsFor=3} }); var teamStatCalculator = new TeamStatCalculator(mockTeamStatRepo.Object); var result = teamStatCalculator.GetTotalGoalsForSeason(1); we should get this back from the method Assert.True(result==6); }

Cấu trúc unit test

Unit test của chúng ta nên follow theo cách tiếp cận “AAA”:

Arrange làm các công việc cài đặt hay chuẩn bị dữ liệu cần thiết;

Act là thực thi function hay method cần được test và lấy kết quả.

Assert là verify kết quả trả (actual result) ra có đúng như mong muốn không (expected result)

Chúng ta có thể thấy một mớ test code xuất hiện trong phần Arrange. Đó là chúng ta tạo một mock cho IteamStatRepository và định nghĩa vài hành vi của nó cũng như dữ liệu sẽ trả về nếu gọi hàm FindAll(). Chúng ta sẽ inject đối tượng vừa mock vào TeamStatCalculator khi tạo ra nó.

Nếu chúng ta không cho phép inject Repository từ ngoài vào thì không thể giả lập được nó và setup được các hành vi như FindAll() trả về cái gì được mà nó sẽ bị đóng gói cứng ở trong triển khai của TeamStatRepository rồi, vậy là DI rất quan trọng cho unit test.

Khi setup hoàn thành, act sẽ đơn giản là gọi method cần test với GetTotalGoalsForSeason(1) tham số là 1 và nhận kết quả. Chỉ có một dòng nhỏ trong test nhưng nếu bạn hạy test khi debug bạn sẽ thấy nó thực sự kỳ diệu. Đây là sự kỳ diệu của IoC/DI. Chúng ta hoàn toàn nghịch đảo việc tạo repository và có thể khiến nó làm bất cứ điều gì.

Cuối cùng, trong phần assert của chúng ta, bạn biết sẽ có 6 bàn thắng trong test data và vì thế phương thức của bạn làm việc đúng.

Chạy unit test trong Visual Studio với Test Explorer và nhận kết quả pass màu xanh.

Thay vào đó, bạn có thể run test với command line trong công cụ CLI mới. Trong thư mục project đơn giản là run dotnet test để chạy test runner từ command line.

Unit test controller

Controller là một thành phần quan trọng trong ứng dụng chúng tôi Core, chúng ta cũng phải test nó để đảm bảo toàn bộ luồng hoạt động trơn chu. Chúng ta thường muốn controller của mình nhỏ và không thực hiện bất cứ logic nào hoặc là truy cập dữ liệu. Chúng ta chỉ cần verify là controller action nhận đầu vào sau trả ra kết quả là được.

Hãy viết unit test cho method Index() trong HomeController

public IActionResult Index([FromServices] IGameRepository gameRepository) { var model = new IndexViewModel { Players = _playerRepository.GetAll().ToList(), Games = gameRepository.GetTodaysGames().ToList() }; return View(model); }

Sau đó chúng ta có hàm test:

[Fact] public void Index_returns_viewresult_with_list_of_players_and_games() { var mockPlayerRepo = new Mock(); { new Player {Name = "Sidney Crosby"}, new Player {Name="Patrick Kane"} }); var mockGameRepo = new Mock(); { new Game { HomeTeam = "Montreal Canadiens", AwayTeam = "Toronto Maple Leafs", Date = DateTime.Today}, new Game { HomeTeam = "Calgary Flames", AwayTeam = "Vancouver Canucks", Date = DateTime.Today}, new Game { HomeTeam = "Los Angeles Kings", AwayTeam = "Anaheim Ducks", Date = DateTime.Today}, }); var controller = new HomeController(mockPlayerRepo.Object); var result = controller.Index(mockGameRepo.Object); var viewResult = Assert.IsType(result); var model = Assert.IsAssignableFrom(viewResult.ViewData.Model); Assert.Equal(2, model.Players.Count); Assert.Equal(3, model.Games.Count); }

Không có gì khác biệt hơn khi chúng ta test TeamStatCalculator. Chúng ta cũng vẫn dùng “AAA” và mock vài thành phần phụ thuộc cần có cho controller này như PlayerRepository hay GameRepository, inject chúng vào controller sau đó gọi hàm Index(). Sự khác nhau lớn nhất là phần assert nơi chúng ta kiểm tra ViewResult và model để chắc chắn là nó trả về kết quả đúng. Hơn nữa, đảm bảo rằng controller cũng được test.

Tóm lại

Ok vậy là chúng ta đã tìm hiểu về Unit test trong .NET Core thông qua ví dụ, chúng ta thấy rằng việc viết unit test rất quan trọng và quan trọng hơn là code của chúng ta phải có IoC và DI để hỗ trợ việc test. Nó giúp ứng dụng của chúng ta tăng chất lượng code giảm rủi ro khi thay đổi và giảm effort test lại khi có thay đổi.

Những lợi ích này là không thể phủ nhận, để các bạn nắm rõ hơn về unit test trong dự án thực tế các bạn có thể tham gia khóa học Kỹ thuật Unit test cho .NET Developer tại TEDU

Tác giả: Bạch Ngọc Toàn

Chú ý: Tất cả các bài viết trên chúng tôi đều thuộc bản quyền TEDU, yêu cầu dẫn nguồn khi trích lại trên website khác.

Unit Testing Ứng Dụng C# Dùng .Net Core Và Visual Studio Code

Trong bài này tôi sẽ chia sẻ cách viết unit test một ứng dụng C# ( Khóa học C# tại Techmaster) đơn giản bằng test framework xUnit, tập trung vào giới thiệu cách sử dụng .NET Core CLI và Visual Studio Code.

Tạo 1 .NET Core solution

Khi các bạn làm quen lần đầu, để tạo 1 ứng dụng HelloWorld ai cũng từng chạy câu lệnh `dotnet new console -o HelloWorld`. Câu lệnh trước sẽ tạo một ứng project dạng console. Vậy nếu chương trình của bạn lớn hơn và muốn có nhiều projects (console, class hay tests) trong cùng 1 chỗ và quản lý chung thì làm sao?

cd Desktop # chuyển đường dẫn đến chỗ bạn muốn chứa solution dotnet new sln -o UnitTestXunit # tạo 1 solution tên UnitTestXunit

Quan tâm đến lập trình, bạn đang tìm hiểu về C#, hay muốn bắt đầu một công việc mới hay nâng cao kĩ năng, Techmaster luôn có chương trình thực tập giúp các bạn phát triển kĩ năng cũng như hỗ trợ tìm kiếm công việc.

Tạo Các Projects Bên Trong Solution

Bây giờ bạn đã 1 .NET Core solution và có thể tạo ra nhiều projects con bên trong. Chúng ta sẽ tạo 1 MathLib class và 1 xUnit test project.

Tạo C# Class

cd UnitTestXunit dotnet new classlib -o MathLib # Tạo 1 MathLib class dotnet sln add ./MathLib/MathLib.csproj # Thêm class project vào trong solution

Tạo xUnit Test Project

Với test project, chúng ta cũng cần thêm reference đến class MathLib mà ta sẽ kiểm thử

mkdir MathLib.Tests cd MathLib.Tests dotnet new xunit # Tạo xUnit test template dotnet add reference ../MathLib/MathLib.csproj # Thêm reference đến class cần kiểm thử cd .. dotnet sln add ./MathLib.Tests/MathLib.Tests.csproj

Sau khi hoàn thành các bước trên, bạn sẽ có 1 solution UnitTestXunit trong đó chứa 2 projects con là class MathLib và xUnit test project MathLib.Tests như sau

Giả lập MathLib class của chúng ta sẽ có các hàm để tính toán. Tên class mặc định là Class1, tôi sẽ đổi cả tên file `Class1.cs` và tên class trong file thành *SimpleMath*. Class này chứa 4 phương thức tính cộng, trừ, nhân, chia, số dư của số nguyên như sau

Viết test cases kiểm thử các phương thức trên

Chuyển sang folder MathLib.Tests, mặc định file test ban đầu là `UnitTest1.cs` và tên class cũng vậy, tôi sẽ đổi thành *SimpleMathTest*. Lúc này class SimpleMathTest sẽ là 1 bộ test dùng để kiểm thử class SimpleMath của MathLib. Mỗi phương thức trong class này sẽ là 1 test case. Lưu ý, nên đặt tên phương thức có nghĩa, ví dụ kiểm thử phương thức `Add` thì tên test case cũng như tên phương thức là `AddTest`, không nên chỉ để `Test1`, `Test2`,...

using System; using Xunit; using MathLib; namespace MathLib.Tests { public class SimpleMathTest { [Fact] public void AddTest() { var res = SimpleMath.Add(1, 2); Assert.True(3 == res); } [Fact] public void SubtractTest() { var res = SimpleMath.Subtract(10, 3); Assert.True(7 == res); } [Fact] public void MultiplyTest() { var res = SimpleMath.Multiply(7, 6); Assert.Equal(42, res); } [Fact] public void DivideTest() { var res = SimpleMath.Divide(21, 3); Assert.Equal( 7, res); } [Fact] public void RemainderTest() { var res = SimpleMath.Remainder(19, 4); Assert.Equal( 3, res); } } }

Trong 1 test framework, bạn sẽ có các hàm để so sánh kết quả. xUnit có các `Assertion` phương thức, trong ví dụ trên, để so sánh 2 kết quả bạn có thể dùng `Assert.Equal(kết quả mong đợi, kết quả thực tế)` hoặc `Assert.True(phép so sánh)`.

[Fact] vs [Theory]

Trong xUnit, bạn có 2 thuộc tính (attributes) là `[Fact]` và `[Theory]` để xác định 2 kiểu test cases. Với `[Fact]` bạn có 1 unit test bình thường như mọi framework khác và phương thức test này không nhận tham số đầu vào nào hết.

`[Theory]` thường được dùng nếu bạn muốn chạy cùng 1 test với 1 bộ dữ liệu, phương thức test lúc này sẽ nhận tham số đầu vào. Đi cùng với [Theory], bạn có thể dùng thêm `[InlineData()]` để truyền dữ liệu cho test cases. Áp dụng `[Theory]`, ta có thể viết test cases như sau:

using System; using Xunit; using MathLib; namespace MathLib.Tests { public class SimpleMathTest { [Theory] [InlineData(1, 2, 3)] [InlineData(-10, 2, -8)] [InlineData(100, 72, 172)] public void AddTest(int a, int b, int expectedRes) { var res = SimpleMath.Add(a, b); Assert.True(expectedRes == res); } [Theory] [InlineData(1, 2, -1)] [InlineData(-25, -10, -15)] [InlineData(9, 5, 4)] public void SubtractTest(int a, int b, int expectedRes) { var res = SimpleMath.Subtract(a, b); Assert.True(expectedRes == res); } [Theory] [InlineData(1, 2, 2)] [InlineData(-25, -10, 250)] [InlineData(0, 5, 0)] public void MultiplyTest(int a, int b, int expectedRes) { var res = SimpleMath.Multiply(a, b); Assert.Equal(expectedRes, res); } [Theory] [InlineData(100, 2, 50)] [InlineData(-25, 1, -25)] [InlineData(0, 5, 0)] public void DivideTest(int a, int b, int expectedRes) { var res = SimpleMath.Divide(a, b); Assert.Equal( expectedRes, res); } [Theory] [InlineData(100, 2, 0)] [InlineData(-25, 4, -1)] [InlineData(11, 3, 2)] public void RemainderTest(int a, int b, int expectedRes) { var res = SimpleMath.Remainder(a, b); Assert.Equal( expectedRes, res); } } }

Các bạn có thể thấy, khi chúng ta có nhiều bộ dữ liệu muốn kiểm tra, ta có thể dùng `[Theory]` để chạy 1 test case qua tất cả các trường hợp dữ liệu.

Chạy Test

Để chạy test, bạn có thể gọi `dotnet test` luôn khi đang ở ngoài solution hoặc chỏ đường dẫn trên terminal vào MathLib.Tests

dotnet test

Nếu test thất bại, xUnit sẽ thông báo test case nào thất bại cũng như kết quả của test case đó

Quan tâm đến lập trình, bạn đang tìm hiểu về C#, hay muốn bắt đầu một công việc mới hay nâng cao kĩ năng, Techmaster luôn có chương trình thực tập giúp các bạn phát triển kĩ năng cũng như hỗ trợ tìm kiếm công việc.

Cập nhật thông tin chi tiết về Viết Unit Test Trong C# Với Nunit trên website Ezlearning.edu.vn. Hy vọng nội dung bài viết sẽ đáp ứng được nhu cầu của bạn, chúng tôi sẽ thường xuyên cập nhật mới nội dung để bạn nhận được thông tin nhanh chóng và chính xác nhất. Chúc bạn một ngày tốt lành!