JUnit test framework cung cấp cho chúng ta các gói lớp có sẵn cho phép chúng ta viết các phương thức test một cách dễ dàng . TestRunner sẽ chạy các test và trả về kết quả là các Test
Trang 3Phân chia công việc
8.Test Exception 9.Junit in Eclipse 10.Các công cụ Testing khác
Trang 4xUnit Framework
Nó liên quan đến việc kiểm tra các đơn vị cơ bản của phần mềm Những đoạn code của unit testing hướng tới mục tiêu là các đơn vị đối tượng cụ thể nào đó , kiểm tra đầu vào đầu ra , một chi tiết một thời điểm cụ thể
xUnit framework là họ của các unit testing frameworks với những ngôn ngữ và các nền tảng lập trình khác nhau
Danh sách unit testing framework :
Trang 5Lịch sử phát triển Junit
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
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
o Vào giữa những năm 90 của thế kỷ 20 , Kent Beck đã phát triển một bộ test xUnit đầu tiên cho Smalltalk
o Beck và Gamma phát triển JUnit trên một chuyến bay từ Zurich đến
Washington, DC.Từ đó Junit trở thành công cụ chuẩn cho Test-Driven
Development trong Java
o Ngày nay, JUnit được tích hợp sẵn trong các Java IDEs (Eclipse, BlueJ, Jbuilder, DrJava)
Trang 6Kiến trúc tổng quan
Trang 7 JUnit test framework cung cấp cho chúng ta các gói lớp có sẵn cho phép chúng ta viết các phương thức test một cách dễ dàng
TestRunner sẽ chạy các test và trả về kết quả là các Test Results
Các lớp của chương trình test chúng ta sẽ được kế thừa các lớp trừu tượng TestCase
Khi viết các Test Case chúng ta cần biết và hiểu lớp
Assert class
Một số định nghĩa trong mô hình tổng quát :
o Test case : test case định nghĩa môi trường mà nó có thể sử dụng để chạy nhiều test khác nhau
o TestSuite : testsuite là chạy một tập các test case và nó cũng có thể bao gồm nhiều test suite khác test suite chính là tổ hợp các test
Trang 8Tại sao phải tạo 1 testsuit
Obviously you have to test your code—right?
You can do ad hoc testing (running whatever tests occur to you at
the moment), or
You can build a test suite (a thorough set of tests that can be run at any time)
Disadvantages of a test suite
It’s a lot of extra programming
True, but use of a good test framework can help quite a bit
You don’t have time to do all that extra work
time more than the amount spent building the test suite
Advantages of a test suite
Reduces total number of bugs in delivered code
Makes code much more maintainable and refactorable
Trang 9 Thông thường JUnit tự động tạo ra các Test Suite ứng với mỗi Test Case Tuy nhiên bạn muốn tự tạo các
Test Suite của riêng mình bằng cách tổ chức
các Test vào Test Suite JUnit cung cấp lớp
junit.framework.TestSuite hỗ trợ việc tạo các Test
Suite
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 reflection.
Tại sao phải tạo 1 testsuit
Trang 10Bằng cách truyền đối tượng TestGame.class vào
construtor TestSuite, bạn đang thông báo cho JUnitbiế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
Trang 11TestSuite suite = new TestSuite();
suite.addTest( new TestGame(" testCreateFighter ")); suite.addTest( new TestGame(" testSameFighters "));
return suite;
}
}
Trang 12public class TestBowl extends TestCase {
} //Test my class Bowl
Name of class is important – should be of the form TestMyClass or MyClassTest
This naming convention lets TestRunner automatically find your test classes
Trang 13Cách viết 1 phương thức trong TestCase
Pattern follows programming by contract paradigm:
Set up preconditions
Exercise functionality being tested
Check postconditions
Example:
public void testEmptyList() {
Bowl emptyBowl = new Bowl();
assertEquals(“Size of an empty list should be zero.”,
0, emptyList.size());
assertTrue(“An empty bowl should report empty.”, emptyBowl.isEmpty()); }
Things to notice:
Specific method signature – public void testWhatever()
o Allows them to be found and collected automatically by JUnit
Coding follows pattern
Notice the assert-type calls…
Trang 14public class Person {
private String firstName;
private String lastName;
public Person(String firstName, String lastName) {
if (firstName == null && lastName == null ) {
throw new IllegalArgumentException( "Both names cannot be null" ); }
this firstName = firstName;
this lastName = lastName;
}
public String getFullName() {
String first = ( this firstName != null ) ? this firstName : "?" ;
String last = ( this lastName != null ) ? this lastName : "?" ;
Trang 15Person p = new Person( "Aidan", "Burke" );
assertEquals( "Aidan Burke" , p.getFullName()); }
/**
* Xac nhan rang nulls da duoc xu ly chinh xac
*/
public void testNullsInName() {
Person p = new Person( null, "Burke" );
assertEquals( "? Burke" , p.getFullName());
p = new Person( "Tanner", null );
assertEquals( "Tanner ? ", p.getFullName());
}
}
Trang 16Các phương thức assertXXX()
Các ph ươ ng th c ứ assertXXX() đượ c dùng đ ki m tra các ể ể
đi u ki n khác nhau ề ệ junit.framework.TestCase, l p cha ớ cho t t c các test case, th a k t l p ấ ả ừ ế ừ ớ
Trang 17 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
Trang 18Các phương thức assert()
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
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ệ
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
Chú ý: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.
Trang 19 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.
Trang 20Thế nào là một unit test tốt
Trang 22Sau đó ta viết một đoạn test sau đây:
Ship fighter2 = this game.createFighter(" 001 ");
assertSame(“ CreateFighter with same id should return same object ", fighter, fighter2);
assertTrue(" A new game should not be started yet", !this game.isPlaying()); }
Trang 23 Mỗi unit test 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 test không liên
quan với nhau lại vào trong một phương thức testXXX()
Đâ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.
Trang 24Ship fighter2 = this game.createFighter(" 001 ");
assertSame(“ CreateFighter with same id should return same object", this fighter, fighter2); System.out.println(" End testSameFighters() ");
Trang 25 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
Trang 26Set Up và Tear Down
Hai phương thức setUp() và tearDown() là một phần của
lớp junit.framework.TestCase.
Khi sử dụng 2 phương thức setUp() và tearDown() 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.JUnit tuân theo các bước sau cho mỗi phương thức test:
o Gọi phương thức setUp() của test case
o Gọi phương thức test
o 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 test trong test case.
Trang 27this game = new Game();
this fighter = this game.createFighter(" 001 "); }
public void tearDown() {
this game.shutdown();
}
Trang 29 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. ọ
Đô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 ụ ẽ ọ ệ ử ụ ớ
Trang 30Person p = new Person(" Aidan", "Burke ");
assertEquals(" Aidan Burke ", p.getFullName()); }
public void testNullsInName() {
Person p = new Person(null, " Burke ");
assertEquals(" ? Burke ", p.getFullName());
p = new Person(" Tanner ", null);
assertEquals(" Tanner ? ", p.getFullName()); }
Trang 32 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 ủ ớ
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 ớ
Trang 35Các công cụ Testing khác
Cactus:
phía bên server của Java
HttpUnit:
các server HTTP
Nunit:
.NET Khởi đầu nó cũng được bắt đầu từ JUnit, nó là một công cụ
hỗ trợ việc unit testing cho Microsoft.NET
Trang 36Các hướng nghiên cứu phát triển
Trang 38Xin cảm ơn