Unit Test là gì? Unity liệu có hỗ trợ Unit Test hay không? Nếu có thì áp dụng Unit Test cho Unity kiểu gì? Trong bài viết này, ta sẽ giải đáp những thắc mắc trên và nêu lên nhưng khải niệm cơ bản liên quan tới Unity Unit Test để hiểu hơn phần nào về nó. Nội dung của bài viết bao gồm:
- Unit Test là gì
- Ý nghĩa của Unit Test
- Unit Test hoạt động như nào trong Unity
- Viết và chạy thử Unit Test
Unit Test là gì?
Trước khi bắt tay vào code, ta phải hiểu được Unit Test là gì. Đúng như tên gọi của nó, Unit Test thì là…Unit Test. Hiểu nôm na đó là một đoạn code để test một đoạn code khác có hoạt động đúng hay không. Điều quan trọng cần lưu ý là mỗi Unit Test chỉ nên sử dụng để test duy nhất một vấn đề
Ngoài ra, còn một lưu ý nữa. Để viết được Unit Test, các hàm cần viết làm sao cho có thể “test được”. Ví dụ như hàm dưới đây:
Ta viết một hàm mà ở đó, người dùng sẽ nhập một tên bất kỳ và hàm chỉ trả về trong trường hợp tên đó không có chứa số và nhỏ hơn hoặc bằng 10 ký tự
Có thể nhận định hàm trên là hàm “test được” vì hàm được chia làm ba phần cụ thể tương ứng với ba unit:
- Nếu trong tên không phải toàn bộ là dạng chữ cái, hàm sẽ thoát ra và không trả về tên đã được nhập
- Nếu tên có chiều dài quá 10 ký tự, hàm cũng sẽ lại thoát ra và không trả về tên đã được nhập
- Chỉ khi tên vượt qua được 2 điều kiện trên thì hàm lúc đó mới trả về tên mà người dùng đã nhập
Ý nghĩa của Unit Test
Vậy làm thế nào để áp dụng Unit Test cho hàm UpdateNameWithCharacter? Ta cần bao nhiêu hàm Unit Test? Một hay nhiều hàm?
Trước khi bắt tay vào viết Unit Test, ta cần nghĩ thật kỹ xem ta cần test những gì và từ đó nghĩ ra cái tên phù hợp cho từng Unit Test. Như ví dụ dưới đây, tên nên đảm bảo rằng nêu rõ nội dung được test, không quan trọng dài hay ngắn, miễn sao nó dễ hiểu và rõ ràng:
UpdateNameDoesntAllowCharacterAddingToNameIfNameIsTenMoreCharactersInLength
UpdateNameDoesntAllowNonLettersToBeAddedToName
UpdateNameAllowLettersToBeAddedToName
Mỗi Unit Test được tạo ra sẽ là một phần của bộ test. Một bộ test chứa tất cả các Unit Test. Bộ test có tác dụng sử dụng để test một chức năng cụ thể nào đó. Như ví dụ trên là một bộ test bao gồm ba Unit Test sử dụng để test một chức năng duy nhất là UpdateNameWithCharacter. Nếu có bất kỳ Unit Test nào trong một bộ test bị false thì coi như bộ test đó bị false. Bộ test chỉ đúng khi toàn bộ Unit Test trả về true
Unit Test trong Unity
Để sử dụng Unit Test trong Unity, trước hết ta cần tìm hiểu về Test Runner của Unity. Test Runner hỗ trợ chạy Unit Test và hiển thị kết quả một cách trực quan. Để ở Unity Test Runner, chọn Window -> General -> Test Runner
Tiếp đó, tạo một Folder để chứa các bộ test. Trong cửa sổ Test Runner ta sẽ thấy 2 tab đó là PlayMode và EditMode. Khi PlayMode được chọn, bộ test sẽ được chạy trong PlayMode. Còn đối với EditMode, bộ test sẽ chạy bên ngoài PlayMode
Cuối cùng, tạo test script bên trong Folder Tests vừa tạo:
Sau một lượt cài đặt rắc rối thì cuối cùng đã tới lúc bắt tay vào code
Mở Game lên và chơi
Cho dễ hiểu, ta sẽ lấy một Game quen thuộc để viết Unit Test. Đó là Game “Bắn thiên thạch”
Trong Game, ta sẽ điều khiển một chiếc máy bay, bay vòng vèo bằng các nút điều hướng, nhấn Space để bắn nổ hết những chiếc thiên thạch ngáng đường ta. Mỗi lần phá được thiên thạch, điểm sẽ được công thêm. Nếu ta đâm vào thiên thạch thì Game sẽ kết thúc và hiển thị lên màn hình Game Over. Nhấn Start Game để chơi lại từ đầu
Viết và chạy thử Unit Test
Bây giờ ta lại tiếp tục đặt câu hỏi. Vậy ta test gì bây giờ? Có gì để test không?
Thật sự thì một Game nhỏ như vậy nhưng có vô số thứ để test. Nhưng trong bài viết này, ta sẽ chỉ quan tâm tới một số vấn đề có thể nhìn thấy rõ ràng và trực quan nhất như va chạm hay core gameplay.
Với Unit Test đầu tiên, ta sẽ test thử xem những chiếc thiên thạch có thực sự di chuyển xuống dưới hay không. Sẽ thật khó để cho thiên thạch va vào tàu khi mà nó lại cứ di chuyển ra xa khỏi tàu phải không! Dưới đây là hàm test được viết cho trường hợp này:
Dù chỉ dó vài dòng code nhưng có khá nhiều thứ đã diễn ra. Ta sẽ đi lần lượt từng dòng và đảm bảo hiểu hết được chúng có tác dụng gì
- Thuộc tính [UnityTest] nhằm mục đích nói với Unity compiler hiểu rằng đây là một Unit Test. Nó sẽ làm hàm này được hiển thị lên trong Test Runner khi mà ta chạy test
- Tạo một instance của Game
- Spawn một thiên thạch và lưu lại trong một biến tạm
- Lấy vị trí theo chiều y của thiên thạch, sử dụng để lưu trữ và so sánh sau này
- Chờ một khoảng thời gian để thiên thạch có thể di chuyển
- Assert.Less là một phương thức được cung cấp bởi NUnit để check giá trị sau có nhỏ hơn giá trị trước hay không. Ngoài ra NUnit còn cùng cấp rất nhiều phương thức khác nữa. Ta có thể đọc thêm về phương thức của NUnit ở link cuối bài viết.
- Cuối cùng nhưng cũng không kém phần quan trọng. Dọn dẹp những thứ bừa bộn ta đã tạo ra, hủy instance của Game
Vậy là xong, ta đã viết được một Unit Test cho Game của mình. Đến lúc tận hưởng thành quả. Mở lại Unity lên ta sẽ thấy Unit Test AsteroidsMoveDown hiện lên trong Test Runner Window như kế hoạch
Hình tròn màu xám ở đây nghĩa là bộ test chưa được chạy. Khi chạy test mà test thành công thì hình tròn sẽ chuyển thành tích xanh, ngược lại sẽ là dấu x đỏ. Chạy test bằng cách ấn nút RunAll
Unity sẽ tạo một Scene tạm và chạy test trong Scene đó. Khi mà chạy xong, ta sẽ thấy được kết quả
Như kế hoạch, tất cả đều đã xanh hết
Vậy là ta đã thành công trong việc tạo Unit Test cho Project của mình
Dù vậy, đây mới chỉ là giới thiệu cho phần Unit Test, không có bất kì kỹ thuật nâng cao nào cả. Unit Test là một phần khá rộng và theo nhận xét thì việc viết Unit Test thậm chí còn tốn thời gian hơn việc phát thiển tính năng. Nhưng đổi lại, nó sẽ giúp cho dự án trở nên chất lượng hơn, giúp ta tự tin hơn khi code, giảm nhẹ phần công việc cho bên Tester.
Tham khảo:
https://www.raywenderlich.com/9454-introduction-to-unity-unit-testing
[Tutorial] Viết Unit Test trong C# với NUnit
NUnit: https://docs.nunit.org/2.5.4/assertions.html
Project Game “Bắn thiên thạch”: https://drive.google.com/file/d/1OiDoXIy7YM6EZyW4aoEwpxdarO-tms6_/view?usp=sharing