Trong thế giới thực, việc viết bài kiểm tra đơn vị cho mã của người khác là hoàn toàn bình thường. Chắc chắn, nhà phát triển ban đầu đã thực hiện điều này rồi, nhưng thường thì bạn sẽ nhận được mã kế thừa khi việc này chưa được thực hiện. Nhân tiện, không quan trọng là mã kế thừa đó đã xuất hiện từ nhiều thập kỷ trước từ một thiên hà xa, rất xa hay liệu một trong những đồng nghiệp của bạn đã kiểm tra nó trong tuần trước hay liệu bạn đã viết nó ngày hôm nay, mã kế thừa là mã mà không cần kiểm tra
Hãy tự hỏi: tại sao chúng ta viết bài kiểm tra đơn vị? Đi đến Green rõ ràng chỉ là một phương tiện để kết thúc, mục tiêu cuối cùng là chứng minh hoặc bác bỏ các xác nhận về mã đang được thử nghiệm.
Giả sử bạn có một phương pháp tính căn bậc hai của một số dấu phẩy động. Trong Java, giao diện sẽ định nghĩa nó là:
public double squareRoot(double number);
Không quan trọng bạn đã viết bản thực hiện hay liệu người khác đã làm, bạn muốn khẳng định một vài thuộc tính của SquareRoot:
- rằng nó có thể trả về các gốc đơn giản như sqrt (4.0)
- rằng nó có thể tìm thấy một gốc thực sự như sqrt (2.0) với độ chính xác hợp lý
- rằng nó tìm thấy sqrt (0,0) là 0,0
- rằng nó ném IllegalArgumentException khi được cấp số âm, tức là trên sqrt (-1.0)
Vì vậy, bạn bắt đầu viết những điều này như các bài kiểm tra cá nhân:
@Test
public void canFindSimpleRoot() {
assertEquals(2, squareRoot(4), epsilon);
}
Rất tiếc, thử nghiệm này đã thất bại:
java.lang.AssertionError: Use assertEquals(expected, actual, delta) to compare floating-point numbers
Bạn đã quên về số học dấu phẩy động. OK, bạn giới thiệu double epsilon=0.01
và đi:
@Test
public void canFindSimpleRootToEpsilonPrecision() {
assertEquals(2, squareRoot(4), epsilon);
}
và thêm các bài kiểm tra khác: cuối cùng
@Test
@ExpectedException(IllegalArgumentException.class)
public void throwsExceptionOnNegativeInput() {
assertEquals(-1, squareRoot(-1), epsilon);
}
và rất tiếc, một lần nữa:
java.lang.AssertionError: expected:<-1.0> but was:<NaN>
Bạn nên thử nghiệm:
@Test
public void returnsNaNOnNegativeInput() {
assertEquals(Double.NaN, squareRoot(-1), epsilon);
}
Chúng ta đã làm gì ở đây? Chúng tôi bắt đầu với một vài giả định về cách thức hoạt động của phương pháp và thấy rằng không phải tất cả đều đúng. Sau đó, chúng tôi đã tạo ra bộ thử nghiệm Green, để viết ra bằng chứng rằng phương thức này hoạt động theo các giả định đã sửa của chúng tôi. Bây giờ khách hàng của mã này có thể dựa vào hành vi này. Nếu ai đó đã trao đổi việc triển khai thực tế của SquareRoot với một thứ khác, ví dụ như thứ gì đó thực sự đã tạo ra một ngoại lệ thay vì trả lại NaN, các thử nghiệm của chúng tôi sẽ nắm bắt được điều này ngay lập tức.
Ví dụ này là tầm thường, nhưng thường thì bạn thừa hưởng những đoạn mã lớn mà không rõ nó thực sự làm gì. Trong trường hợp đó, việc đặt một khai thác thử nghiệm xung quanh mã là bình thường. Bắt đầu với một vài giả định cơ bản về cách thức hoạt động của mã, viết các bài kiểm tra đơn vị cho chúng, kiểm tra. Nếu Green, tốt, viết nhiều bài kiểm tra. Nếu màu đỏ, bây giờ bạn có một xác nhận thất bại rằng bạn có thể chống lại một thông số kỹ thuật. Có lẽ có một lỗi trong mã kế thừa. Có thể thông số kỹ thuật không rõ ràng về đầu vào cụ thể này. Có lẽ bạn không có thông số kỹ thuật. Trong trường hợp đó, hãy viết lại bài kiểm tra sao cho ghi lại hành vi không mong muốn:
@Test
public void throwsNoExceptionOnNegativeInput() {
assertNotNull(squareRoot(-1)); // Shouldn't this fail?
}
Theo thời gian, bạn kết thúc với một khai thác thử nghiệm ghi lại cách mã thực sự hoạt động và trở thành một loại thông số được mã hóa. Nếu bạn muốn thay đổi mã kế thừa hoặc thay thế nó bằng một mã khác, bạn có khai thác thử nghiệm để xác minh rằng mã mới hoạt động giống nhau hoặc mã mới hoạt động khác nhau theo cách được mong đợi và được kiểm soát (ví dụ: thực tế nó là mã sửa lỗi mà bạn mong đợi nó sẽ sửa). Khai thác này không phải hoàn thành vào ngày đầu tiên, trên thực tế, có một khai thác không đầy đủ hầu như luôn luôn tốt hơn so với không có khai thác nào cả. Có một khai thác có nghĩa là bạn có thể viết mã khách hàng của mình dễ dàng hơn, bạn biết nơi mong đợi mọi thứ sẽ bị phá vỡ khi bạn thay đổi một cái gì đó và nơi chúng bị phá vỡ khi cuối cùng chúng đã làm.
Bạn nên cố gắng thoát ra khỏi suy nghĩ rằng bạn phải viết bài kiểm tra đơn vị chỉ vì bạn phải làm, giống như bạn sẽ điền vào các trường bắt buộc trên một biểu mẫu. Và bạn không nên viết bài kiểm tra đơn vị chỉ để làm cho dòng màu đỏ màu xanh lá cây. Bài kiểm tra đơn vị không phải là kẻ thù của bạn, bài kiểm tra đơn vị là bạn của bạn.