Invariant Tests

Trong bài viết này, sẽ trình bày khái niệm kiểm thử bất biến (Invariant-Test) trong ngôn ngữ lập trình Java.

Nội dung bài viết

  • Khái niệm
  • Cách dùng
  • Ưu nhược điểm
  • Ví dụ mẫu
  • Tham khảo

Khái niệm

Trước khi đi sâu vào tìm hiểu invariant test, hãy tìm hiểu khái niệm contract programming.

A design by contract scheme

Đây là một hướng tiếp cận thiết kế phần mềm. Với quy ước, nhà thiết kế phần mềm phải định nghĩa các đặc tả rõ ràng và có thể xác thực được.
 Các đặc tả đó là mở rộng của khái niệm kiểu dữ liệu trừu tượng với pre-condition, post-condition và invariant. Nói cách khác, phần mềm cần phải
 thỏa mãn các điều kiện tiên quyết và tính bất biến. Từ đó ra đời khái niệm kiểm thử bất biến của chương trình.

Cách dùng

Đối với Java, Invariant test không được hỗ trợ trực tiếp mà gián tiếp thông qua từ khóa assert.
 Thư viện Java hỗ trợ hai kiểu sử dụng assert:

  • assert expression1;
  • assert expression1 : expression2;

Assert có thể dùng để kiểm tra nội tại bất biến trong phương thức.
 chẳng hạn, ta có thể dùng để kiểm tra giả định của mình đối với giá trị của biến:

if (i % 3 == 0) {
...
} else if (i % 3 == 1) {
...
} else {
assert i % 3 == 2 : i;
...
}

ví dụ trên cho thấy biến i được ta giả định chắc chắn nó phải là 2 trong trường hợp này.

Kiểm tra điều kiện tiên quyết (pre-condition)
 Theo quy ước, precondition của public method sẽ buộc dùng để kiểm tra parameter và ném ngoại lệ được chỉ định rõ. 
 Nguyên nhân như vậy là do : assert được thiết kế để kiểm tra tính đúng đắn của chương trình, không được dùng để xử lý ngoại lệ.
 Khi assert false, nó sẽ ném AssertionError, ngoại lệ chung và không rõ ràng để lập trình viên có thể xử lý.

Còn đối với private method, ta có thể dùng để kiểm tra tính đúng đắn của biến — bất kể người dùng có nhập liệu gì đi chăng nữa.
 Khi ta viết assert ngay trước khi thực hiện các operation, ta đang thực hiện kiểm tra một precondition:

/**
* Sets the refresh interval (which must correspond to a legal frame rate).
*
* @param interval refresh interval in milliseconds.
*/
private void setRefreshInterval(int interval) {
// PRECONDITION - Confirm adherence to precondition in nonpublic method
assert interval > 0 && interval <= 1000/MAX_REFRESH_RATE : interval;

... // Set the refresh interval
}

Kiểm tra điều kiện sau (post-condition):
 Ta có thể dùng assert để kiểm tra post-condition của cả public lẫn private method. Sau một loạt các operation trong method, 
 ta viết assert trước khi phương thức kết thúc chính là một post condition:

/**
* Returns a BigInteger whose value is (this-1 mod m).
*
* @param m the modulus.
* @return this-1 mod m.
* @throws ArithmeticException m <= 0, or this BigInteger
*has no multiplicative inverse mod m (that is, this BigInteger
*is not relatively prime to m).
*/
public BigInteger modInverse(BigInteger m) {
if (m.signum <= 0)
throw new ArithmeticException("Modulus not positive: " + m);
... // Do the computation
assert this.multiply(result).mod(m).equals(ONE) : this;
return result;
}

Khi nào thì dùng assert?

Khuyến khích nên dùng khi ta cần kiểm tra tính đúng đắn của chương trình:

  • Kiểm tra pre-condition, post-condition, invariant của biến/ phương thức.
  • Kiểm tra thứ mà không nên xảy ra

Ưu/ nhược điểm của assert trong Java

Ưu điểm

  • Cách nhanh, hiệu quả để phát hiện và gỡ đúng lỗi.
  • Có thể xem như là một tài liệu của dự án, làm tăng tính bảo trì.
  • Thường được dùng để kiểm tra tính logic của chương trình.

Nhược điểm

  • Có thể làm chậm chương trình khi xác nhận một biểu thức/ phương thức nào đó
  • Dừng chương trình ngay lập tức nếu biểu thức assert trả về False

Ví dụ mẫu: example source code

NA

Tham khảo

Show your support

Clapping shows how much you appreciated Phạm Xuân Trường’s story.