Ở Phần 1 Cách viết Unit Test trong C# chúng ta đã hoàn thành viết 1 test method đầu tiên và chạy nó. Phần này sẽ hướng dẫn quá trình phần tích, phát triển unit test và tái cấu trúc, nó có thể giúp cho code của bạn hiệu quả hơn.
Phân tích các vấn đề
sau khi đã passed được test method đầu tiên. chúng ta cần quay lại các trường hợp còn lại
- Method ném ra Exception
ArgumentOutOfRangeException
Nếu số tiền rút lớn hơn số tiền có trong tài khoản. - Method ném ra Exception
ArgumentOutOfRangeException
nếu số tiền rút nhỏ hơn 0.
Tạo các test method
Đầu tiên chúng ta sẽ thêm vào một test method sau:
//unit test method [TestMethod] [ExpectedException(typeof(ArgumentOutOfRangeException))] public void Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange() { // arrange double beginningBalance = 11.99; double debitAmount = -100.00; BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance); // act account.Debit(debitAmount); // assert is handled by ExpectedException }
Chúng ta sử dụng thuộc tính ExpectedExceptionAttribute để khẳng định rằng ngoại lệ phải đã được ném ra. Thuộc tính này sẽ làm cho test method failed nếu lỗi ArgumentOutOfRangeException không được ném ra. Chúng chạy test với cả debitAmount
âm và dương và chúng ta nhận được ApplicationException , khi amount nhỏ hơn 0 chúng ta thấy test method này hoạt động đúng.
Để test cho trường hợp số tiền rút lớn hơn số dư, chúng ta cần làm như sau:
- Tạo một phương pháp thử nghiệm mới có tên Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange.
- Sao chép các phương pháp cơ thể từ Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange đến phương thức mới.
- Đặt debitAmount đến một số lớn hơn số dư.
Chạy Test method
Chạy 2 test methods với 2 giá trị choh debitAmout khác nhau để thể hiện rằng các bài kiểm tra xử lý đầy đủ các trường hợp còn lại của chúng ta. Chạy 2 test methods và kiểm tra xác nhận rằng tất cả các trường hợp trong phân tích ban đầu của chúng ta là đúng.
Tiếp tục phân tích
khi bạn chạy 2 test methods cuối, chúng ta chỉ nhận được 1 ArgumentOutOfRangeException chung chung mà không biết chính xác được trường hợp nào xảy ra.
Chúng ra hãy xem lại hàm Debit trong class BankAccount. và chúng ta sẽ thấy được chỉ có 1 ArgumentOutOfRangeException được ném ra cho 2 trường hợp
throw new ArgumentOutOfRangeException("amount");
Cấu trúc lại code sau kiểm thử
với class BankAccount
Thêm
// class under test public const string DebitAmountExceedsBalanceMessage = "Debit amount exceeds balance"; public const string DebitAmountLessThanZeroMessage = "Debit amount less than zero";
update lại hàm Debit
// method under test // ... if (amount > m_balance) { throw new ArgumentOutOfRangeException("amount", amount, DebitAmountExceedsBalanceMessage); } if (amount < 0) { throw new ArgumentOutOfRangeException("amount", amount, DebitAmountLessThanZeroMessage); } // ...
Cấu trúc lại test methods
đầu tiên chúng ta sẽ xóa thuộc tính ExpectedException
. chúng ta sẽ catch ngoại lệ được ném ra và xác định tính đúng đắn của nó. Chúng ta có 2 lựa chọn để làm việc này.
Ví dụ Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
method:
- Cần xác định
ActualValue
property của exception (Tham số thứ 2 củaArgumentOutOfRangeException
constructor) là lớn hơn balance. Tùy chọn này đòi hỏi rằng chúng ta phải kiểm tra thuộc tính ActualValue của ngoại lệ đối với biến startBalance của phương pháp thử và cũng yêu cầu xác minh rằng ActualValue lớn hơn không. - Chúng ra sẽ xác nhận message của
ArgumentOutOfRangeException
có đúng không.
Phương thức StringAssert.Contains trong Microsoft unit test framework cho phép chúng ta xác minh tùy chọn thứ hai mà không có các tính toán được yêu cầu của tùy chọn đầu tiên.
[TestMethod] public void Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange() { // arrange double beginningBalance = 11.99; double debitAmount = 20.0; BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance); // act try { account.Debit(debitAmount); } catch (ArgumentOutOfRangeException e) { // assert StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage); } }
Kiểm tra lại, viết lại và phân tích lại
Khi chúng ta kiểm tra lại các phương pháp thử nghiệm với các giá trị khác nhau, chúng ta gặp các sự kiện sau:
- Nếu chúng ta bắt lỗi chính xác bằng cách sử dụng một khẳng định tại đó debitAmount lớn hơn số dư, khẳng định đó pass, ngoại lệ sẽ bị bỏ qua, và do đó phương pháp thử nghiệm pass. Đây là hành vi chúng ta muốn.
- Nếu chúng ta sử dụng một debitAmount nhỏ hơn 0, khẳng định này sẽ không thành công vì thông báo lỗi sai sẽ được trả về. Xác nhận cũng không thành công nếu chúng ta giới thiệu một ngoại lệ tạm thời ArgumentOutOfRange tại một điểm khác. Điều này cũng tốt.
- Nếu giá trị debitAmount có giá trị (nghĩa là ít hơn số dư nhưng lớn hơn số không) thì không có trường hợp ngoại lệ nào bị bắt, do đó khẳng định không bao giờ bị bắt, Phương pháp thử nghiệm được pass. Điều này không tốt vì chúng ta muốn phương pháp thử nghiệm thất bại nếu không Ngoại lệ bị ném.
Phiên bản cuối cùng của chúng ta Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange trông giống như sau:
[TestMethod] public void Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange() { // arrange double beginningBalance = 11.99; double debitAmount = 20.0; BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance); // act try { account.Debit(debitAmount); } catch (ArgumentOutOfRangeException e) { // assert StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage); return; } Assert.Fail("No exception was thrown."); }
Trong phần cuối cùng này, công việc mà chúng tôi đã cải tiến mã kiểm tra của chúng tôi dẫn đến các phương pháp kiểm tra mạnh mẽ hơn và có tính thông tin hơn. Nhưng quan trọng hơn, phân tích thêm cũng dẫn đến mã tốt hơn trong dự án của chúng ta đang được kiểm tra.
Bài viết Phần 2: Sử dụng Unit Test để cải thiện code được dịch từ
https://msdn.microsoft.com/en-us/library/ms182532.aspx
Pingback: Phần 1: Cách viết Unit Test trong C# | Phạm Duy Anh