Phần 2: Sử dụng Unit Test để cải thiện code

Ở 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

  1. 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.
  2. 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

One thought on “Phần 2: Sử dụng Unit Test để cải thiện code

  1. Pingback: Phần 1: Cách viết Unit Test trong C# | Phạm Duy Anh

Leave a Reply

Your email address will not be published.