Công cụ automated unit testing cho java là gì
JUnit là một framework đơn giản dùng cho việc tạo các unit testing tự động, và chạy các test có thể lặp đi lặp lại. Nó chỉ là một phần của họ kiến trúc xUnit cho việc tạo các unit testing. JUnit là một chuẩn trên thực tế cho unit testing trong Java. JUnit về nguồn gốc được viết bởi 2 tác giả Erich Gamma và Kent Beck
Các test case của JUnit là các lớp của Java, các lớp này bao gồm một hay nhiều các phương thức unit testing, và những test này lại được nhóm thành các Test Suite. Mỗi phương thức test trong JUnit phải được thực thi nhanh chóng. Tốc độ là điều tối quan trọng vì càng nhiều test được viết và tích hợp vào bên trong quá trình xây dựng phần mềm, cần phải tốn nhiều thời gian hơn cho việc chạy toàn bộ Test Suites. Các lập trình viên không muốn bị ngắt quãng trong một khoãng thời gian dài trong khi các test chạy, vì thế các test mà chạy càng lâu thì sẽ có nhiều khả năng là các lập trình viên sẽ bỏ qua bước cũng không kém phần quan trọng này. Các test trong JUnit có thể là các test được chấp nhận hay thất bại, các test này được thiết kế để khi chạy mà không cần có sự can thiệp của con người. Từ những thiết kế như thế, bạn có thể thêm các bộ test vào quá trình tích hợp và xây dựng phần mềm một cách liên tục và để cho các test chạy một cách tự động
Ta có một lớp Person như sau:
Sau đó ta sẽ viết một test case đơn giản để test một số phương thức của lớp trên import junit.framework.TestCase;
Lưu ý: mỗi unit test là một phương thức public và không có tham số được bắt đầu bằng tiếp đầu ngữ test. Nếu bạn không tuân theo quy tắc đặt tên này thì JUnit sẽ không xác định được các phương thức test một các tự động. Để biên dịch TestPerson, chúng ta phải khai báo gói thư viện junit trong biến đường môi trường classpath set classpath=%classpath%;.;junit.jar javac TestPerson Để chạy một JUnit TestCase, ta có 2 cách • Chạy với môi trường text, các bạn gõ lệnh java junit.textui.TestRunner TestPerson Sau khi chạy sẽ có kết quả như hình trên. • Chạy với môi trường đồ họa java junit.swingui.TestRunner TestPerson Chúng ta có thể chạy trực tiếp các TestCase mà không muốn kích hoạt một trong các test runner của JUnit. Chúng ta sẽ thêm phương thức main() vào test case. Ví dụ
Phương thức Mô tả assertEquals() So sánh 2 giá trị để kiểm tra bằng nhau. Test sẽ được chấp nhận nếu các giá trị bằng nhau assertFalse() Đánh giá biểu thức luận lý. Test sẽ được chấp nhận nếu biểu thức sai assertNotNull() So sánh tham chiếu của một đối tượng với null. Test sẽ được chấp nhận nếu tham chiếu đối tượng khác null assertNotSame() So sánh địa chỉ vùng nhớ của 2 tham chiếu đối tượng bằng cách sử dụng toán tử ==. Test sẽ được chấp nhận nếu cả 2 đều tham chiếu đến các đối tượng khác nhau assertNull() So sánh tham chiếu của một đối tượng với giá trị null. Test sẽ được chấp nhận nếu tham chiếu là null assertSame() So sánh địa chỉ vùng nhớ của 2 tham chiếu đối tượng bằng cách sử dụng toán tử ==. Test sẽ được chấp nhận nếu cả 2 đều tham chiếu đến cùng một đối tượng assertTrue() Đánh giá một biểu thức luận lý. Test sẽ được chấp nhận nếu biểu thức đúng fail() Phương thức này làm cho test hiện hành thất bại, phương thức này thường được sử dụng khi xử lý các biệt lệ Mặc dù bạn có thể chỉ cần sử dụng phương thức assertTrue() cho gần như hầu hết các test, tuy nhiên thì việc sử dụng một trong các phương thức assertXXX() cụ thể sẽ làm cho các test của bạn dễ hiểu hơn và cung cấp các thông điệp thất bại rõ ràng hơn. Tất cả các phương thức của bảng trên đều nhận vào một String không bắt buộc làm tham số đầu tiên. Khi được xác định, tham số này cung cấp một thông điệp mô tả test thất bại. Ví dụ: assertEquals(employeeA, employeeB); assertEquals(“Employees should be equal after the clone() operation.”, employeeA, employeeB). Phiên bản thứ 2 được ưa thích hơn vì nó mô tả tại sao test thất bại, điều này sẽ giúp cho việc sửa lỗi được dễ dàng hơn
Code:
Sau đó ta viết một đoạn test sau đây: Code:
Đây là một thiết kế không tốt vì mỗi phương thức assertXXX() đang kiểm tra phần không liên quan của chức năng. Nếu phương thức assertEquals thất bại, phần còn lại của test sẽ không được thi hành. Khi xảy ra điều này thì chúng ta sẽ không biết các test khác có đúng chức năng hay không. Tiếp theo chúng ta sẽ sửa test trên lại để kiểm tra các khía cạnh khác nhau của trò chơi một cách độc lập. Code:
Với cách tiếp cận này, khi một test thất bại sẽ không làm cho các mệnh đề assertXXX() còn lại bị bỏ qua. Có thể bạn sẽ đặt ra câu hỏi có khi nào một phương thức test chứa nhiều hơn một các phương thức assertXXX() hay không? Câu trả lời là có. Nếu bạn cần kiểm tra một dãy các điều kiện và các test theo sau sẽ luôn thất bại nếu có một test đầu tiên thất bại, khi đó bạn có thể kết hợp nhiều phương thức assert vào trong một test
Quá trình này được lặp lại đối với mỗi phương thức test trong test case. Sau đây chúng ta sẽ xem xét 1 ví dụ Code:
Thông thường bạn có thể bỏ qua phương thức tearDown() vì mỗi unit test riêng không phải là những tiến trình chạy tốn nhiều thời gian, và các đối tượng được thu dọn khi JVM thoát. tearDown() có thể được sử dụng khi test của bạn thực hiện những thao tác như mở kết nối đến cơ sở dữ liệu hay sử dụng các loại tài nguyên khác của hệ thống và bạn cần phải dọn dẹp ngay lập tức. Nếu bạn chạy một bộ bao gồm một số lượng lớn các unit test, thì khi bạn trỏ tham chiếu của các đối tượng đến null bên trong thân phương thức tearDown() sẽ giúp cho bộ dọn rác lấy lại bộ nhớ khi các test khác chạy Đôi khi bạn muốn chạy vài đoạn mã khởi tạo chỉ một lần, sau đó chạy các phương thức test, và bạn chỉ muốn chạy các đoạn mã dọn dẹp chỉ sau khi tất cả test kết thúc. Ở phần trên, JUnit gọi phương thức setUp() trước mỗi test và gọi tearDown() sau khi mỗi test kết thúc, vì thế để làm được điều như trên, chúng ta sẽ sử dụng lớp junit.extension.TestSetup để đạt được yêu cầu trên. Ví dụ sau sẽ minh họa việc sử dụng lớp trên Code:
TestSetup là một lớp thừa kế từ lớp junit.extension.TestDecorator, Lớp TestDecorator là lớp cơ sở cho việc định nghĩa các test biến thể. Lý do chính để mở rộng TestDecorator là để có được khả năng thực thi đoạn mã trước và sau khi một test chạy. Các phương thức setUp() và tearDown() của lớp TestSetup được gọi trước và sau khi bất kỳ Test nào được truyền vào constructor, Trong ví dụ trên chúng ta đã truyền một tham số có kiểu TestSuite vào constructor của lớp TestSetup TestSetup setup = new TestSetup(new TestSuite(TestPerson.class)) { Điều này có nghĩa là 2 phương thức setUp() được gọi chỉ một lần trước toàn bộ bộ test và tearDown() được gọi chỉ một lần sau khi các test trong bộ test kết thúc. Chú ý: các phương thức setUp() và tearDown() bên trong lớp TestPerson vẫn được thực thi trước và sau mỗi phương thức test bên trong lớp TestPerson.
public static Test suite() { … } Nếu không thấy phương thức trên, JUnit sẽ sử dụng kỹ thuật reflection để tự động xác định tất cả các phương thức testXXX() trong test case của bạn, rồi thêm chúng vào một test suite. Sau đó nó sẽ chạy tất cả các test trong suite này. Bạn có thể tạo ra bản sao hành vi của phương thức suite() mặc định như sau Code:
Bằng cách truyền đối tượng TestGame.class vào construtor TestSuite, bạn đang thông báo cho JUnit biết để xác định tất cả các phương thức testXXX() trong lớp đó và thêm chúng vào suite. Đoạn mã trên không làm khác gì so với việc JUnit tự động làm, tuy nhiên bạn có thể thêm các test cá nhân để chỉ chạy các test nhất định nào đó hay là điều khiển thứ tự thực thi Code:
Bạn có thể kết hợp nhiều suite vào các suite khác. Bạn có ra ở đây đã sử dụng mẩu Composite. Ví dụ: Code:
Bây giờ khi bạn chạy test case này, bạn sẽ chạy tất cả các test bên trong lớp TestGame và lớp TestPeson
Code:
Tham số đầu tiên của RepeatedTest là một Test cần chạy, tham số thứ 2 là số lần lặp lại. Vì TestSuite cài đặt interface Test nên chúng ta có thể lặp lại toàn bộ test như trên. Tiếp theo là ví dụ mô tả cách xây dựng một test suite mà trong đó các test khác nhau được lặp đi lặp lại khác nhau: Code:
Code:
0 Nói chung bạn chỉ nên sử dụng kỹ thuật này khi bạn mong đợi một exception xảy ra. Đối với các điều kiện lỗi khác bạn nên để exception chuyển sang cho JUnit. Khi đó JUnit sẽ bắt lấy và tường trình 1 lỗi test. |