Bạn đang xem bài viết Tìm Hiểu Unit Testing Trongcore đượ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.
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 Test Dùng Để Làm Gì Và Kinh Nghiệm Viết Unit Test Tốt Nhất
Đâu là sự khác biệt giữa một unit test tốt và dở? Làm thế nào để bạn có thể viết được các unit test tốt? Điều này không được rõ ràng lắm. Thậm chí nếu bạn là một lập trình viên tài ba với nhiều thập niên kinh nghiệm, kiến thức và thói quen hiện tại của bạn sẽ không tự động giúp bạn viết ra được các unit test tốt, bởi vì nó là một dạng khác của lập trình và hầu hết mọi người bắt đầu với giả định sai lầm vô ích về những gì mà các unit test cần phải đạt được.
Hầu hết các unit test mà tôi thấy là khá vô ích. Tôi không đổ lỗi cho các nhà phát triển phần mềm: thông thường, anh ta hoặc cô ta khi được yêu cầu viết unit test, thì họ sẽ cài đặt NUnit và bắt đầu tung ra một loạt các [Test] method. Một khi họ nhìn thấy những đèn đỏ và xanh lá cây, thì họ cho rằng mình đã làm việc đó một cách chính xác. Đó là một giả định tồi! Điều đó rất dễ viết ra những unit test tồi mà thêm rất ít giá trị cho một dự án trong khi lạm phát chi phí thay đổi mã nguồn thì tăng theo cấp số nhân. Điều đó có làm bạn bận tâm?
Unit test không phải dùng để tìm bugVì vậy, nếu bạn đang cố gắng tìm kiếm bug, thì có một cách hiệu quả hơn nhiều đó là hãy chạy toàn bộ ứng dụng với nhau như nó sẽ chạy trong môi trường thực tế, giống như bạn làm công việc kiểm tra thủ công một cách tự nhiên vậy. Nếu bạn tự động hóa kiểu test này để phát hiện những sai sót khi chúng xảy ra trong tương lai, đây được gọi là integration testing và thường sử dụng các kỹ thuật và công nghệ khác hơn là unit test. Bạn có muốn sử dụng các công cụ thích hợp nhất cho mỗi công việc không?
Tìm kiếm bug (những thứ không làm việc như bạn muốn)
Kiểm thử thủ công (đôi khi cả kiểm thử tích hợp tự động)
Phát hiện hồi quy (những thứ đang làm việc tốt nhưng đã bất ngờ ngừng hoạt động)
Các kiểm thử tích hợp tự động (đôi khi cũng bao gồm cả kiểm thử thủ công, mặc dù khá tốn thời gian)
Thiết kế các thành phần trong phần mềm mạnh mẽ
Unit testing (trong quy trình TDD)
(Lưu ý: có một ngoại lệ, nơi các unit test rất hiệu quả trong việc phát hiện bug. Đó là khi bạn đang tái cấu trúc code của một đơn vị (unit) nhưng không có nghĩa là để thay đổi hành vi của nó. Trong trường hợp này, các unit test có thể cho bạn biết nếu hành vi của đơn vị (unit) đó có thay đổi hay không.)
Vậy nếu unit test không phải để tìm bug, thì nó để làm gì?Tôi cá là bạn đã nghe câu trả lời này hàng trăm lần rồi, nhưng vì quan niệm sai lầm cố hữu trong kiểm thử cứ treo lơ lửng trong tâm trí của các nhà phát triển phần mềm, tôi sẽ nói lại cái nguyên tắc của nó. Một bậc thầy về TDD đã nói rằng, “TDD là một quá trình thiết kế, chứ không phải là một quá trình kiểm thử”. Hãy để tôi giải thích thêm: TDD là một cách mạnh mẽ trong việc thiết kế các thành phần phần mềm (“units”) tương tác để hành vi của chúng được xác định thông qua các unit test. Tất cả chỉ có vậy!
Những unit test tốt vs dởTDD sẽ giúp bạn cung cấp các thành phần phần mềm hoạt động theo thiết kế của bạn. Một bộ unit test tốt là vô cùng có giá trị: nó là tài liệu thiết kế của bạn, khiến cho việc tái cấu trúc và mở rộng code của bạn được dễ dàng hơn trong khi giữ lại một cái nhìn tổng quan rõ ràng về hành vi của mỗi thành phần. Tuy nhiên, một bộ unit test tồi là vô cùng đau thương: nó chẳng chứng tỏ bất cứ điều gì rõ ràng cả, và có thể làm cản trở nghiêm trọng khả năng tái cấu trúc hoặc thay đổi code của bạn theo bất kỳ cách nào.
Các kiểm thử của bạn nằm ở đâu trên thang mức độ sau?
Ở đầu kia của thang mức độ, các kiểm thử tích hợp (integration test) không biết về cách codebase của bạn được chia nhỏ thành các đơn vị (unit), nhưng thay vào đó nó cho thấy cách toàn bộ hệ thống ứng xử đối với người dùng bên ngoài như thế nào. Chúng có chi phí hợp lý để duy trì (vì không quan trọng việc bạn tái cấu trúc hoạt động nội bộ trong hệ thống của bạn như thế nào, nó sẽ không ảnh hưởng đến hành vi bên ngoài) và chúng chứng tỏ được rất nhiều về những tính năng thực sự làm việc hiện nay.
Bí quyết để viết những unit test tuyệt vờiHãy làm cho mỗi test độc lập với tất cả những phần khác
Bất kỳ hành vi nhất định nào cũng nên được xác định tại một và chỉ duy nhất một test. Nếu không, sau này khi bạn thay đổi hành vi đó, bạn sẽ phải thay đổi rất nhiều test. Các hệ quả của nguyên tắc này bao gồm:
Đừng làm những assertion không cần thiết
Những hành vi cụ thể nào mà bạn đang kiểm thử? Nó sẽ gây phản tác dụng nếu cứ Assert() bất cứ thứ gì mà cũng đã được assert bằng test khác: nó chỉ làm tăng tần suất của những thất bại vô nghĩa mà chẳng cải thiện unit test một chút nào cả. Điều này cũng áp dụng cho việc gọi Verify() không cần thiết – nếu nó không phải là hành vi cốt lõi dưới test đó, thì hãy dừng việc quan sát về nó! Đôi khi, cộng đồng TDD thường diễn đạt điều này bằng cách nói rằng “chỉ có duy nhất một assertion hợp lý trên mỗi test”.
Hãy nhớ rằng, các unit test là một thiết kế chỉ rõ một hành vi nào đó sẽ làm việc như thế nào, không phải là một danh sách các quan sát của tất cả mọi thứ mà phần code đó thực hiện.
Kiểm thử chỉ một unit code tại một thời điểm
Kiến trúc của bạn phải hỗ trợ việc testing units (tức là, các class hoặc mọi nhóm rất nhỏ của các class) độc lập, chứ không phải là tất cả chúng kết lại với nhau. Nếu không, bạn sẽ có rất nhiều chồng chéo giữa các test, vì vậy việc thay đổi một unit ảnh hưởng ra bên ngoài và gây ra thất bại ở khắp mọi nơi.
Nếu bạn không thể làm được điều này, thì kiến trúc của bạn đang làm hạn chế chất lượng công việc của bạn – hãy xem xét sử dụng Inversion of Control.
Giả lập tất cả những dịch vụ và trạng thái bên ngoài
Nếu không, hành vi trong những dịch vụ bên ngoài sẽ chồng chéo lên nhiều test, và trạng thái dữ liệu khác nhau trong mỗi unit test có thể ảnh hưởng đến kết quả của nhau.
Bạn chắc chắn phải nhận một kết quả sai nếu chạy các test của mình theo một thứ tự xác định, hoặc nếu chúng chỉ làm việc khi cơ sở dữ liệu hoặc kết nối mạng của bạn đang hoạt động.
Tránh những điều kiện tiên quyết không cần thiết
(Bằng cách này, tôi sẽ không tính đẩy nhiều điểm dữ liệu thông qua các test tương tự (ví dụ, bằng cách sử dụng các [TestCase] API của NUnit) là vi phạm quy tắc độc lập này. Quá trình test có thể hiển thị nhiều thất bại nếu một cái gì đó thay đổi, nhưng nó vẫn chỉ có một phương pháp test để duy trì, vì vậy điều đó cũng tốt.)
Đừng sử dụng unit test trong phần thiết lập cấu hình
Theo định nghĩa, các thiết lập cấu hình của bạn không phải là một phần của bất kỳ unit code nào (đó là lý do tại sao bạn trích xuất các thiết lập ra khỏi code của unit của bạn). Ngay cả khi bạn có thể viết một unit test để kiểm tra cấu hình của mình, nó chỉ đơn thuần buộc bạn phải xác định cấu hình tương tự tại một vị trí dự phòng bổ sung. Xin chúc mừng: nó chứng tỏ rằng bạn có thể copy và paste!
Cá nhân tôi coi việc sử dụng những thứ như các filter trong chúng tôi MVC như là cấu hình. Các filter như [Authorize] hoặc [RequiresSsl] là các cấu hình tùy chọn gắn vào trong code của bạn. Bằng mọi cách viết một kiểm thử tích hợp (integration test) cho các hành vi bên ngoài-quan sát được (externally-observable), nhưng nó là vô nghĩa để thử unit testing cho sự hiện diện của các thuộc tính của filter trong mã nguồn của bạn – một lần nữa nó chỉ chứng tỏ rằng bạn có thể copy và paste. Điều đó không giúp bạn thiết kế bất cứ điều gì, và nó sẽ chẳng bao giờ phát hiện bất kỳ lỗi nào cả.
Đặt tên các unit test của bạn một cách rõ ràng và nhất quán
Nếu bạn đang kiểm thử action Purchase của ProductController hành động như thế nào khi hết hàng trong kho (stock is zero), sau đó có thể có một lớp test fixture được gọi là PurchasingTests cùng với một unit test gọi là ProductPurchaseAction_IfStockIsZero_RendersOutOfStockView(). Cái tên này mô tả đối tượng (action Purchase của ProductController), kịch bản (hết hàng trong kho), và kết quả (hiển thị trên view là “hết hàng”). Tôi không biết liệu có một cái tên cho mô hình đặt tên này hay không, mặc dù tôi biết nhiều người khác cũng làm theo cách này.
Tránh sử dụng những tên unit test không rõ nghĩa như Purchase() hoặc OutOfStock(). Việc bảo trì sẽ rất khó khăn nếu bạn không biết là mình đang cố duy trì cái gì.
Kết luậnKhông còn nghi ngờ gì nữa, unit testing có thể làm tăng đáng kể chất lượng dự án của bạn. Nhiều người trong ngành cho rằng việc có thêm bất kỳ unit test thì tốt hơn là không có gì, nhưng tôi không đồng tình với quan điểm đó: một bộ test có thể là một tài sản tuyệt vời, hoặc nó có thể là một gánh nặng rất lớn mà không mang lại giá trị gì nhiều. Nó phụ thuộc vào chất lượng của những test này, mà dường như được xác định bởi mức độ các nhà phát triển hiểu rõ những mục tiêu và nguyên tắc của unit testing.
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 TestTrướ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.
Nhập Môn Unit Testing Trong .Net
Unit Testing là phương pháp kiểm thử phần mềm dựa trên các đơn vị kiểm thử (hay unit test). Trong các ngôn ngữ hướng đối tượng (ví dụ C#), các đơn vị kiểm thử này có thể là các phương thức hay lớp. Một đơn vị kiểm thử được dùng để kiểm tra một đơn vị công việc (unit of work) với một kết quả giả định nào đó; Nếu kết quả thực thi của đơn vị công việc cần kiểm tra khác với kết quả giả định thì đơn vị kiểm thử thất bại.
Các đặc điểm của một đơn vị kiểm thử tốt
Tự động và có thể lặp
Dễ dàng thực thi
Có thể dùng trong tương lai
Chạy nhanh
Kết quả nhất quán
Kiểm soát đầy đủ hay toàn quyền (full control) các thành phần kiểm thử
Độc lập với các đơn vị kiểm thử khác
Khi thất bại, dễ dàng phát hiện ra những gì được mong đợi và xác định hướng giải quyết
Framework cho Unit TestingUnit Testing có thể được thực hiện dễ dàng nhờ các framework. Framework phổ biến hỗ trợ cho các nhà phát triển .NET là NUnit vì nó dễ dùng, dễ nhớ, có nhiều tính năng nổi trội và dễ dàng cài đặt đến Visual Studio qua . Bên cạnh NUnit, một vài framework có thể được cân nhắc sử dụng cho dân .NET là xUnit hay (của Microsoft). Đối với các ngôn ngữ khác có thể sử dụng danh sách các framework tại https://en.wikipedia.org/wiki/List_of_unit_testing_frameworks
Tạo dự án kiểm thửTrong bài viết này, chúng ta sẽ minh học kỹ thuật Unit Testing bằng cách sử dụng framework NUnit trong Visual Studio 2023 Community. Để đơn giản, chúng ta sẽ tạo một dự án Console App (.NET Framework) tên UnitTestingDemo và thêm một lớp tên Calculator đến dự án này. Thay đổi nội dung tập tin chúng tôi như sau:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace UnitTestingDemo { public class Calculator { public int Add(int a, int b) { return a + b; } public int Sub(int a, int b) { return a - b; } } }Trong cửa sổ New Project chọn Class Library (.NET Framework), đặt tên lớp là Calculator_Test:
Nhấn OK. Đổi tên tập tin chúng tôi trong dự án Calculator_Test vừa tạo thành chúng tôi
Cài đặt NUnitTrong cửa sổ NuGet – Solution chọn tab Browse và gõ cụm từ ‘ nunit ‘ trong ô tìm kiếm và chọn NUnit đầu tiên:
Bên khung cửa sổ NUnit bên phải chọn Project (bao gồm hai dự án) và nhấn Install:
Nếu hộp thoại Preview Changes xuất hiện thì nhấn OK. Nếu cài đặt thành công thì kết quả từ hộp thoại Output sẽ như sau:
Đóng cửa sổ NuGet – Solution và Output. Trở lại cửa sổ Solution Explorer tìm đến mục Reference của hai sự án sẽ xuất hiện nunit.framwork:
Một cách tương tự, chúng ta cũng cài đặt NUnit3TestAdapter:
Mục đích cài đặt thư viện này là để thực thi các đơn vị kiểm thử NUnit trong Visual Studio.
Như vậy chúng ta đã cài đặt thành công NUnit. Kế tiếp, chúng ta sẽ tìm hiểu một vài thuộc tính và lớp quan trọng trước khi tiến hành kiểm thử.
Các thuộc tính TestFixture, Test và lớp AssertNUnit chứa hai thuộc tính TestFixture và dùng để đánh dấu lớp và phương thức sẽ là các đơn vị kiểm thử (unit tests). Trước khi sử dụng hai thuộc tính này, chúng ta cần khai báo thư viện NUnit:
using NUnit.Framework;Chúng ta muốn lớp MyTesting sẽ là lớp kiểm thử, thêm thuộc tính TestFixture và khai báo thư viện NUnit đến tập tin chúng tôi như sau:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using NUnit.Framework; namespace Calculator_Test { [TestFixture] public class MyTesting { } }Lưu ý rằng, thuộc tính TestFixture được đặt trong dấu ngoặc vuông.
Sau khi chọn lớp kiểm thử, chúng ta sẽ xây dựng hai phương thức Add_Test và Sub_Test dùng để kiểm thử các phương thức Add và Sub từ lớp Calculator. Lớp MyTesting được thay đổi như sau:
[TestFixture] public class MyTesting { [Test] public void Add_Test() { } [Test] public void Sub_Test() { } }Thuộc tính Test được đặt trong dấu ngoặc vuông để đánh dấu các phương thức là đơn vị kiểm thử. Trước khi viết vài đoạn mã cho hai phương thức Add_Test và Sub_Test, chúng ta sẽ tìm hiểu lớp Assert từ namespace NUnit.Framework.
Lớp Assert như là chiếc cầu nối giữa mã chương trình cần kiểm thử và NUnit. Một đơn vị kiểm thử sẽ dùng lớp này với mục đích khai báo một giả định nào đó là tồn tại và nếu các đối số được chuyển vào lớp được thực hiện với kết quả khác với giả định thì đơn vị kiểm thử này thất bại.
Thay đối nội dung hai phương thức Add_Test và Sub_Test như sau:
[TestFixture] public class MyTesting { [Test] public void Add_Test() { Calculator cal = new Calculator(); int add_Result = cal.Add(3, 5); Assert.That(add_Result, Is.EqualTo(8)); } [Test] public void Sub_Test() { Calculator cal = new Calculator(); int sub_Result = cal.Sub(3, 5); Assert.That(sub_Result, Is.EqualTo(8)); } }Chúng ta sử dụng phương thức của lớp Assert để xác nhận một kết quả là đúng với giả định hay không. Trong hai phương thức Add_Test và Sub_Test, chúng ta gọi các phương thức Add và Sub từ lớp Calculator với các đối số là 3 và 5. Kết quả từ các phương thức này sẽ được so sánh với kết quả giả định là 8.
Thực hiện kiểm thử với công cụ Test ExplorerChúng ta thực hiện kiểm thử bằng cách dùng công cụ Test Explorer từ mục Test trong Visual Studio 2023:
Cửa sổ Test Explorer như sau:
Chúng ta có thể chọn Run All để chạy cả hai phương thức kiểm thử hay chúng ta có thể chọn một trong hai phương thức và nhấn chuột phải chọn Run Selected Tests, ví dụ chọn Add_Test:
Kết quả:
Như vậy đơn vị kiểm thử Add_Test đã thành công vì tổng 3 và 5 là 8 khớp với kết quả giả định. Tương tự, chúng ta thực thi Sub_Test:
Sub_Test đã thất bại vì kết quả hiệu 3 và 5 là -2 khác với kết quả giả định là 8.
Kết luậnTrong bài viết này chỉ giới thiệu một cách khái quát về kỹ thuật kiểm thử Unit Testing và cách cài đặt cũng như sử dụng framework NUnit trong Visual Studio 2023 Community. Một điều cần lưu ý rằng, để có thể thực hiện thành công việc kiểm thử với NUnit, trong Visual Studio 2023 chúng ta cần cài đặt hai gói thư viện NUnit và NUnit3TestAdapter thông NuGet. Chúng ta cũng đã tìm hiểu các thuộc tính TestFixture, Test và lớp từ namespace NUnit.Framework và cũng đã chạy thử các đơn vị kiểm thử bằng công cụ Test Explorer.
Cập nhật thông tin chi tiết về Tìm Hiểu Unit Testing Trongcore 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!