Your SlideShare is downloading. ×
Adp junit
Adp junit
Adp junit
Adp junit
Adp junit
Adp junit
Adp junit
Adp junit
Adp junit
Adp junit
Adp junit
Adp junit
Adp junit
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Adp junit

770

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
770
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
29
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Testing with JUnit TRƯỜNG ĐẠI HỌC DUY TÂN KHOA ĐÀO TẠO QUỐC TẾ »»»»«««« KIỂM THỬPHẦ MỀM VỚ N I JUnit APPLICATION DEVELOPMENT PRACTICES GVHD: Thầy Võ Văn Lường Thành viên: Mai Văn Minh Huỳnh Ngọc Khoa Hoàng Duy Hưng Trần Thành TâmJUnit testing Page 1
  • 2. Testing with JUnitMục lục1) Giới thiệu .................................................................................................................................................. 32) Ví dụ test các chức năng của một lớp ....................................................................................................... 34) Thế nào là một unit test tốt ....................................................................................................................... 65) Set Up và Tear Down ............................................................................................................................... 76) Tổ chức các test vào các test suite .......................................................................................................... 107) Chạy các test lặp đi lặp lại ...................................................................................................................... 119) Giới thiệu một số công cụ, thư viện nguồn mở hỗ trợ việc test phần mềm ............................................ 12 a) Cactus ................................................................................................................................................. 12 b) HttpUnit .............................................................................................................................................. 12 c) NUnit .................................................................................................................................................. 1210) Tham khảo ............................................................................................................................................ 13JUnit testing Page 2
  • 3. Testing with JUnitKIỂM THỬ PHẦN MỀM VỚI JUnitJUnit là một framework đơn giản dùng cho việc tạo các unit testing tự động, và chạy cáctest 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 unittesting. 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 Beck1) Giới thiệ uJUnit có thể được tải xuống từ địa chỉ http://www.junit.org.JUnit có những đặc điểm đáng lưu tâm như sau:• Xác nhận (assert) việc kiểm tra kết quả được mong đợi• Các Test Suite cho phép chúng ta dễ dàng tổ chức và chạy các test• Hỗ trợ giao diện đồ họa và giao diện dòng lệnhCá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 unittesting, 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àngnhiề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ờigian hơn cho việc chạy toàn bộ Test Suite. Các lập trình viên không muốn bị ngắt quãng trong mộtkhoã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ế để khichạ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ựđộng2) Ví dụ test các chức năng của một lớpBạn muốn viết các unit test với JUnit. Việc đầu tiên bạn phải tạo một lớp con thừa kế từ lớpjunit.framework.TestCase. Mỗi unit test được đại diện bởi một phương thức testXXX() bên trong lớp concủa lớp TestCaseTa có một lớp Person như sau:public class Person {private String firstName;private String lastName;public Person(String firstName, String lastName) {if (firstName == null && lastName == null) {JUnit testing Page 3
  • 4. Testing with JUnitthrow 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 : "?";return first + last;}public String getFirstName() {return this.firstName;}public String getLastName() {return this.lastName;}}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ênimport junit.framework.TestCase;public class TestPerson extends TestCase {public TestPerson(String name) {super(name);}/*** Xac nhan rang name duoc the hien dung dinh dang*/public void testGetFullName() {Person 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());}}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ứctest một các tự động.JUnit testing Page 4
  • 5. Testing with JUnitĐể 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ườngclasspathset classpath=%classpath%;.;junit.jarjavac 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ệnhjava junit.textui.TestRunner TestPersonSau khi chạy sẽ có kết quả như hình trên.• Chạy với môi trường đồ họajava junit.swingui.TestRunner TestPersonChú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ủaJUnit. Chúng ta sẽ thêm phương thức main() vào test case. Ví dụpublic class TestGame extends TestCase {…public static void main(String []args) {junit.textui.TestRunner.run(new TestSuite(TestGame.class))}}3) Cá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 junit.framework.Assert. Lớpnày định nghĩa khá nhiều các phương thức assertXXX(). Các phương thức test hoạt động bằng cách gọinhững phương thức này.Bảng sau mô tả các phương thức assertXXX() khác nhau có trong lớp junit.framework.Assert.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ằngnhauassertFalse() Đánh giá biểu thức luận lý. Test sẽ được chấp nhận nếu biểu thức saiassertNotNull() 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 nullassertNotSame() 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 nhauassertNull() 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ếutham chiếu là nullassertSame() 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ượngassertTrue() Đánh giá một biểu thức luận lý. Test sẽ được chấp nhận nếu biểu thức đúngfail() 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 khixử lý các biệt lệJUnit testing Page 5
  • 6. Testing with JUnitMặ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ơn4) Thế nào là một unit test tốtMỗ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ềutest không liên quan với nhau lại vào trong một phương thức testXXX()Ta có một lớp Game như saupublic class Game {private Map ships = new HashMap();public Game() throws BadGameException {}public void shutdown() {// dummy method}public synchronized Ship createFighter(String fighterId) {Ship s = (Ship) this.ships.get(fighterId);if (s == null) {s = new Ship(fighterId);this.ships.put(fighterId, s);}return s;}public boolean isPlaying() {return false;}}public class BadGameException extends Exception {public BadGameException(String s) {super(s);}}Sau đó ta viết một đoạn test sau đây:public void testGame() throws BadGameException{Game game = new Game();JUnit testing Page 6
  • 7. Testing with JUnitShip fighter = game.createFighter(“001”);assertEquals("Fighter did not have the correct identifier", "001",this.fighter.getId());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());}Đâ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ủachứ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. Khixả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ôngTiế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 độclập.public void testCreateFighter() {System.out.println("Begin testCreateFigher()");assertEquals("Fighter did not have the correct identifier", "001",this.fighter.getId());System.out.println("End testCreateFighter()");}public void testSameFighters() {System.out.println("Begin testSameFighters()");Ship fighter2 = this.game.createFighter("001");assertSame("createFighter with same id should return same object",this.fighter, fighter2);System.out.println("End testSameFighters()");}public void testGameInitialState() {System.out.println("Begin testGameInitialState()");assertTrue("A new game should not be started yet", !this.game.isPlaying());System.out.println("End testGameInitialState()");}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ứcassertXXX() 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 theosau 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ứcassert vào trong một test5) Set Up và Tear DownHai phương thức setUp() và tearDown() là một phần của lớp junit.framework.TestCase Bằng cách sửdụng các phương thức setUp và tearDown. Khi sử dụng 2 phương thức setUp() và tearDown() sẽ giúpchú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ớicủa test case ứng với mỗi phương thức test. Từ đó, nếu bạn có 5 phương thức test thì JUnit sẽ tạo ra 5thể 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ữacá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 chomỗi phương thức test:JUnit testing Page 7
  • 8. Testing with JUnit• Gọi phương thức setUp() của test case• Gọi phương thức test• Gọi phương thức tearDown() của test caseQuá 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ụpublic class Ship {private String id;public Ship(String id) {this.id = id;}public String getId() {return this.id;}}public class TestGame extends TestCase {private Game game;private Ship fighter;public void setUp() throws BadGameException {this.game = new Game();this.fighter = this.game.createFighter("001");}public void tearDown() {this.game.shutdown();}public void testCreateFighter() {System.out.println("Begin testCreateFigher()");assertEquals("Fighter did not have the correct identifier","001", this.fighter.getId());System.out.println("End testCreateFighter()");}public void testSameFighters() {System.out.println("Begin testSameFighters()");Ship fighter2 = this.game.createFighter("001");assertSame("createFighter with same id should return same object",this.fighter, fighter2);System.out.println("End testSameFighters()");}public void testGameInitialState() {System.out.println("Begin testGameInitialState()");assertTrue("A new game should not be started yet",!this.game.isPlaying());System.out.println("End testGameInitialState()");}}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ếntrì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ửJUnit testing Page 8
  • 9. Testing with JUnitdụ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ạità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ộtsố 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ươngthứ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ứcsetUp() 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ênimport junit.extensions.TestSetup;import junit.framework.*;public class TestPerson extends TestCase {public TestPerson(String name) {super(name);}public void testGetFullName() {Person 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());}public static Test suite() {TestSetup setup = new TestSetup(new TestSuite(TestPerson.class)) {protected void setUp() throws Exception {//Thực hiện các đoạn mã khởi tạo một lần ở đây}protected void tearDown() throws Exception {//Thực hiện các đoạn mã dọn dẹp ở đây}};return setup;}}TestSetup là một lớp thừa kế từ lớp junit.extension.TestDecorator, Lớp TestDecorator là lớp cơ sở choviệ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 TestSetupTestSetup 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.JUnit testing Page 9
  • 10. Testing with JUnitChú ý: các phương thức setUp() và tearDown() bên trong lớp TestPerson vẫn được thực thi trước và saumỗi phương thức test bên trong lớp TestPerson.6) Tổ chức các test vào các test suiteThô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ạocá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ớpjunit.framework.TestSuite hỗ trợ việc tạo các Test SuiteKhi 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ạnpublic 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ácphươ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ấtcả 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ư saupublic class TestGame extends TestCase{…public static Test suite() {return new TestSuite(TestGame.class);}}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ônglà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áctest nhất định nào đó hay là điều khiển thứ tự thực thiimport junit.framework.*;public class TestGame extends TestCase {private Game game;private Ship fighter;public TestGame(String name) {super(name);}…public static Test suite() {TestSuite suite = new TestSuite();suite.addTest(new TestGame("testCreateFighter"));suite.addTest(new TestGame("testSameFighters"));return suite;}}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ụ:public static Test suite() {TestSuite suite = new TestSuite(TestGame.class);suite.addTest(new TestSuite(TestPerson.class));JUnit testing Page 10
  • 11. Testing with JUnitreturn suite;}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ớpTestPeson7) Chạ y các test lặp đi lặ p lạ iTrong một vài trường hợp, chúng ta muốn chạy một test nào đó lặp đi lặp lại nhiều lần để đo hiệu suấthay phân tích các vấn đề trục trặc. JUnit cung cấp cho chúng ta lớp junit.extension.RepeatedTest để làmđược điều này. Lớp RepeatedTest giúp chúng ta thực hiện điều này một cách dễ dàngpublic static Test suite() {//Chạy toàn bộ test suite 10 lầnreturn new RepeatedTest(new TestSuite(TestGame.class), 10);}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ì TestSuitecà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âydựng một test suite mà trong đó các test khác nhau được lặp đi lặp lại khác nhau:public static Test suite() {TestSuite suite = new TestSuite();//Lặp lại testCreateFighter 100 lầnsuite.addTest(new RepeatedTest(new TestGame("testCreateFighter"), 100));//Chạy testSameFighters 1 lầnsuite.addTest(new TestGame("testSameFighters"));//Lặp lại testGameInitialState 20 lầnsuite.addTest(new RepeatedTest(new TestGame("testGameInitialState"), 20);return suite;}8) Test các exceptionPhần tiếp đến chúng ta sẽ xem xét đến một phần test cũng quan trọng không kém trong lập trình là testcác exception. Chúng ta sử dụng cặp từ khóa try/catch để bắt các exception như mong đợi, chúng ta sẽgọi phương thức fail() khi exception chúng ta mong đợi không xảy ra. Trong ví dụ sau, constructor củalớp Person nên tung ra IllegalArgumentException khi cả 2 tham số của nó đều mang giá trị null. Test sẽthất bại nếu nó không tung ra exception.public void testPassNullsToConstructor() {try {Person p = new Person(null, null);fail("Expected IllegalArgumentException because both args are null");}catch (IllegalArgumentException expected) {//Bỏ qua phần này không xử lý vì có nghĩa là test được chấp nhận}}JUnit testing Page 11
  • 12. Testing with JUnitNó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ềukiệ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ỗitest.9) Giới thiệ u một số công cụ, thư viện nguồn mở hỗ trợ việ c test phầnmề ma) CactusCactus là một framework unit testing nguồn mở dùng để test cho các đoạn mã phía bên server của Java.Đặc biệt là Cactus cho phép bạn test Servlet, JSP, và Servlet filter. Cactus thừa kế từ JUnit để cung cấp3 lớp con của lớp junit.framework.TestCase là các lớp:• org.apache.cactus.ServletTestCase• org.apache.cactus.JspTestCase• org.apache.cactus.FilterTestCaseMỗi test case của Cactus cung cấp 1 chức năng đặc biệt. Cactus test thực thi trên cả client và server. Khisử dụng Cactus bạn chỉ cần tạo một lớp thừa kế từ 1 trong 3 lớp trên. Sau đó Cactus sẽ tạo ra và chạy 2thể hiện của test case. Một chạy trên JVM ở phía client, cái còn lại chạy bên trong JVM của môi trườngchạy servlet (servlet container) phía server. Bên client phía client cho phép HTTP headers và các thamsố HTTP được thêm vào các yêu cầu đi ra. Bên phía server gọi thực thi các phương thức bên trongservlet của bạn để thực hiện bất kỳ xác nhận nào, và sau đó sẽ gởi phản hồi ngược trở lại cho phíaclient. Tíếp đến bên phía client xác nhận phản hồi từ bên server gởi về có chứa thông tin mong muốnhay không.Bạn có thể download Cactus từ địa chỉ http://jakarta.apache.org/cactusb) HttpUnitHttpUnit là một thư viện nguồn mở của Java được dùng để tương tác với các server HTTP. Với HttpUnit,chương trình Java của bạn có thể truy xuất trực tiếp đến server mà không cần thiết phải sử dụng đếntrình duyệt.HttpUnit cung cấp các API để phân tích HTML, nhận thông tin của biểu mẫu trang web, theo dõi các siêuliên kết, thiết lập cookie và thực hiện các tác vụ khác có liên quan đến trình duyệt web.Ngoài ra nó cũng gồm cả một thư viện để thao tác trực tiếp đến servlet, đôi khi không cần thiết phải khởiđộng web serverThông thường chúng ta sử dụng kết hợp HttpUnit và JUnit để viết các tét. JUnit định nghĩa cácframework dùng để kiểm tra, và các phương thức testXXX() của bạn sẽ sử dụng các hàm API của thưviện HttpUnit để truy cập và kiểm tra trang webBạn có thể download HttpUnit từ địa chỉ http://www.httpunit.orgc) NUnitNUnit là một framework dành cho việc testing unit trong tất cả các ngôn ngữ .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. Nó được viết hoàntoàn bằng C#JUnit testing Page 12
  • 13. Testing with JUnit10) Tham khả o http://www.junit.org Java eXtreme Programming Cookbook – Eric M. Burke & Brian M. Coyner, O’Reilly Test Driven Development By Example – Addison WesleyJUnit testing Page 13

×