Hướng dẫn test code java bằng junit trong eclipse chuỗi

Trong JUnit có các Test Case 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 cần kiểm tra, và Test Case này lại được nhóm với nhau để tạo thành Test Suite. Mỗi phương thức thử trong JUnit phải được thực thi nhanh chóng. Tốc độ ở đây là điều tối quan trọng vì càng nhiều phép thử được viết và tích hợp vào bên trong quá trình phần mềm thì càng tốn nhiều thời gian để hơn cho việc chạy toàn bộ Test Suite.

Những người lập trình không muốn bị ngắt quãng trong một thời gian dài trong khi các phép thử đang chạy, do đó các phép thử mà càng chạy lâu thì sẽ có nhiều khả năng là các lập trình viên sẽ bỏ qua bước này. Các phép thử được thiết kế để khi chạy mà không cần có sự can thiệp của con người.

Mỗi phép thử trong JUnit là một phương thức public, không có đối số và được bắt đầu bằng chữ test ( testXXX()). Nếu chúng ta không tuân thủ theo qui tắc này thì JUnit sẽ không xác định được các phương thức test một cách tự động.

2. Lợi ích của Junit JUnit tránh cho người lập trình phải làm đi làm lại những việc kiểm thử nhàm chán bằng cách tách biệt mã kiểm thử ra khỏi mã chương trình, đồng thời tự động hóa việc tổ chức và thi hành các bộ số liệu kiểm thử.

Thoạt tiên, khi sử dụng JUnit, ta có thể có cảm giác là JUnit chỉ làm mất thêm thời gian cho việc kiểm thử: Thay vì phải viết thêm các lớp và phương thức mới phục vụ cho công tác kiểm thử, ta có thể soạn nhanh một bộ số liệu rồi viết ngay vào trong phương thức main() và quan sát ngay kết quả kiểm thử. Vì quá trình soạn số liệu và quá trình kiểm thử diễn ra đồng thời, nên ta sẽ dễ dàng nhận biết được ngay chương trình đã chạy đúng trên bộ số liệu kiểm thử hay không, mà không cần nhìn vào tín hiệu “xanh” mà JUnit có thể hỗ trợ.

Nhưng khi tổ chức lại chương trình cho hợp lý hơn (refactoring) hoặc khi phải thay đổi chương trình để phục vụ cho nhu cầu mới, các bộ số liệu kiểm thử trước đây sẽ cần được sử dụng lại để chắc chắn rằng những thay đổi trong chương trình không làm phương hại đến những thành quả trước đó, lúc này ta sẽ phải mất thời gian để tìm hiểu lại xem bộ số liệu trước đây sẽ tương ứng với kết xuất gì vì ta không thể nhớ hết mọi hoạt động kiểm thử đã diễn ra. Việc nhớ lại những kiểm thử đã qua sẽ chẳng thú vị vì không đem đến cho ta điều gì mới. Nếu phải kiểm thử trên những bộ số liệu lớn thì gánh nặng của việc tổ chức kiểm thử sẽ chồng chất thêm. JUnit giúp người lập trình tự động hóa các công việc nhàm chán, và chỉ cần nhìn thấy tín hiệu “xanh” là người lập trình có thể an tâm rằng module đã được lập trình đúng.

3. Các phương thức trong JUnit

3.1 assertXXX() Các phương thức dạng assertXXX() được dùng để kiểm tra các điều kiện khác nhau. Dưới đây là mô tả các phương thức assertXXX() khác nhau có trong lớp junit.framework.Assert.

• Boolean assertEquals(): So sánh hai giá trị để kiểm tra bằng nhau. Phép thử thất bại nếu hai giá trị không bằng nhau. • Boolean assertFalse(): Đánh giá biểu thức logic. Phép thử thất bại nếu biểu thức đúng. • Boolean assertNotNull(): So sánh tham chiếu của một đối tượng với Null. Phép thử thất bại nếu tham chiếu đối tượng Null. • Boolean assertNotSame(): So sánh địa chỉ vùng nhớ của hai tham chiếu hai đối tượng bằng cách sử dụng toán tử ==. Phép thử thất bại trả về nếu cả hai đều tham chiếu đến cùng một đối tượng. • Boolean assertNull(): So sánh tham chiếu của một đối tượng với giá trị Null. Phép thử thất bại nếu đối tượng không là Null. • Boolean assertSame(): So sánh địa chỉ vùng nhớ của hai tham chiếu đối tượng bằng cách sử dụng toán tử ==. Phép thử thất bại nếu cả hai không tham chiếu đến cùng một đối tượng. • Boolean assertTrue(): Đánh giá một biểu thức logic. Phép thử thất bại nếu biểu thức sai. • void fail(): Phương thức này làm cho test hiện tại thất bại, phương thức này thường được sử dụng khi xử lý các ngoại lệ.

Chúng ta có thể chỉ sử dụng phương thức assertTrue()cho gần như là hầu hết các test, tuy nhiên việc sử dụng các phương thức assertXXX() cụ thể sẽ tiện lợi hơn cho các test của bạn trong trường hợp cung cấp các thông báo mô tả thất bại. Tất cả các phương thức 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 message mô tả test thất bại. Điều này giúp cho việc sửa lỗi được dễ dàng hơn.

3.2 setUp() và tearDown() Hai phương thức này là một phần của lớp junit.framework.TestCase. Khi sử dụng hai phương thức này sẽ giúp chúng ta tránh được việc trùng mã khi nhiều test cùng chia sẻ nhau ở phần khởi tạo và dọn dẹp các biến. JUnit tuân thủ theo một dãy có thứ tự các sự kiện khi chạy các test. Đầu tiên, nó tạo ra một thể hiện mới của Test Case ứng với mỗi phương thức thử. Từ đó, nếu bạn có 5 phương thức thử thì JUnit sẽ tạo ra 5 thể hiện của Test Case. Vì lý do đó, các biến thể hiện không thể được sử dụng để chia sẻ trạng thái giữa các phương thức test. Sau khi tạo xong tất cả các đối tượng test case, JUnit tuân theo các bước sau cho mỗi phương thức test:

  • • Gọi phương thức setUp() của test case • Gọi phương thức thử • Gọi phương thức tearDown() của test case

Quá trình này được lặp lại đối với mỗi phương thức thử trong Test Case. Thông thường chúng ta có thể bỏ qua phương thức tearDown() vì mỗi phương thức thử 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 máy áo Java (JVM) thoát. Phương thức 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 chúng ta 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.

3.3 Tổ chức các phép thử Mỗi phép thử ( Test Case)chỉ nên kiểm tra phần cụ thể của một chức năng nào đó. Chúng ta không nên kết hợp nhiều phép thử không liên quan đến nhau vào trong cùng một phương thức testXXX(). Một phương thức thử có thể chứa nhiều hơn một phương thức assertXXX(). Khi chúng ta cần kiểm tra một dãy các điều kiện và một phép thử thất bại sẽ khiến các test theo sau thất bại , khi đó chúng ta có thể kết hợp nhiều phương thức assertXXX() vào trong một phương thức thử.

Thông thường thì JUnit sẽ tự động tạo ra các Test Suite ứng với mỗi Test Case. Tuy nhiên, chúng ta cũng có thể tự tạo ra các Test Suite riêng của mình bằng cách tổ chức các Test Case vào Test Suite, được hỗ trợ bởi lớp junit.framework.TestSuite. Test Suite cho phép kết hợp các Test Case để tạo ra một phép thử tổng quát. Khi bạn sử dụng giao diện text hay graphic, JUnit sẽ tìm phương thức sau trong Test Case của bạn:

public static Test suite() { … }

Nếu không thấy phương thức trên, JUnit sẽ sử dụng kỹ thuật ánh xạ để 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:

public class TestXXX extends TestCase{
…
public static Test suite() {
return new TestSuite(TestXXX.class);
}
}

Bằng cách truyền đối tượng TestXXX.class vào hàm khởi tạo TestSuite, chúng ta đang thông báo cho JUnit biết để xác định tất cả các phương thức TestXXX () của lớp TestXXX và thêm chúng vào suite. Chúng ta có thể kết hợp nhiều suite vào các suite khác. Ví dụ như sau:

Code:

public static Test suite() {
TestSuite suite = new TestSuite(TestXXX.class);
suite.addTest(new TestSuite(TestYYY.class));
return suite;
}

Trong một số trường hợp chúng ta muốn chạy test nào đó lặp đi lặp lại nhiều lần để đo hiệu suất hay phân tích các vấn đề trục trặc cần phải giải quyết, JUnit cung cấp cho chúng ta lớp junit.extension. RepeatedTest dùng để giải quyết vấn đề này. Lớp này sẽ giúp chúng ta chạy các test lặp đi lặp lại.

Code:

public static Test suite() {
//Chạy toàn bộ test suite 10 lần
return new RepeatedTest(new TestSuite(TestXXX.class), 10);
}

Như đã biết, chúng ta dùng cặp từ khóa try/catch để bắt các exception như mong đợi. Khi exception chúng ta mong đợi không xảy ra, ta sẽ gọi phương thức fail() của JUnit.