Testdriven Development (TDD) là một kỹ thuật phát triển phần mềm dựa trên sự lặp lại của một chu kỳ phát triển: đầu tiên các nhà phát triển viết một automated test case xác định một cải thiện mong muốn hoặc một chức năng mới, sau đó tạo ra một lượng tối thiểu code để vượt qua test case đó, và cuối cùng cấu trúc lại mã mới với các tiêu chuẩn chấp nhận được.Phát triển dựa trên kiểm thử (TestDriven DevelopmentTDD) là một phương pháp tiếp cận cải tiến để phát triển phần mềm trong đó kết hợp phương pháp Phát triển kiểm thử trước (Test First Development) và phương pháp Điều chỉnh lại mã nguồn (Refactoring). Có quan điểm cho rằng mục tiêu của TDD là đặc tả (specification) chứ không phải là xác nhận tính đúng đắn (validation). Nói cách khác, đó là một cách để nghĩ về thiết kế của bạn trước khi viết mã nguồn cho chức năng. Một quan điểm khác lại cho rằng TDD là một kỹ thuật lập trình. Nhưng nhìn chung, mục tiêu của TDD là viết mã nguồn sáng sủa, rõ ràng và có thể chạy được.
Trang 1BÁO CÁO BÀI TẬP LỚN
NGÀNH : CÔNG NGHỆ THÔNG TIN
ĐỀ TÀI: TEST DRIVEN DEVELOPMENT
DANH SÁCH NHÓM 8:
1.PHẠM ANH ĐẠT (Nhóm trưởng)2.NGUYỄN THỊ LOAN
3.NGUYỄN THỊ ÁNH
Hà Nội, 15/10/2013
Trang 2MỤC LỤC
I Định nghĩa Test-driven Development 4
II Tại sao một phần mềm nên phát triển theo hướng TDD? 5
1 TDD và cách kiểm thử truyền thống 5
2 Tại sao dùng TDD? 6
III Chu trình phát triển 7
1 Add a test 7
2 Run all tests and see if the new one fails 8
3 Write some code 8
4 Run tests 8
5 Refactor code 9
6 Repeat 9
IV Thuận lợi khi sử dụng TDD 9
1 Chất lượng tốt hơn với TDD 9
a Chất lượng trên nhiều khía cạnh 9
b Thời gian cho fix lỗi 11
2 Nhu cầu về việc trao đổi để xác định chức năng 11
3 Có thể làm tài liệu cho nhà phát triển 11
4 Các lập trình viên được làm chủ 11
V Hướng phát triển, áp dụng TDD cho các công nghệ phát triển 11
1 Test_driving với các thành phần web 11
a Test-driving với Java Servlets 11
b Test-driving với Spring controllers 13
2 Test-driving với truy cập dữ liệu 14
3 Test-driving the unpredictable 15
a Test-driving với chức năng theo thời gian 15
b Test-driving với đa luồng 15
4 Test-driving với Swing 15
VI Thách thức 16
1 Thời gian đầu tư lớn 16
Trang 32 Phức tạp hơn 16
3 Gắn liền với thiết kế 16
4 Cần phải tinh chỉnh liên tục 17
5 Liên quan chặt chẽ đến ”Agile” 17
VII Đặc điểm của Unit Test (Kiểm tra bộ phận) 17
1 Định nghĩa: 17
2 Cấu trúc của một UT: 17
3 Đặc điểm của một UT 18
4 Vòng đời của một UT 18
5 Thiết kế UT 18
6 Ứng dụng của UT 19
7 Lợi ích của UT 19
8 Chiến lược viết mã hiệu quả với UT 20
VIII KHUNG KIỂM THỬ PYUNIT 21
1 Khái niệm: 21
2 Những API quan trọng của unittest 21
IX DEMO CHƯƠNG TRÌNH PHÁT TRIỂN THEO HƯỚNG TDD SỬ DỤNG PYUNIT 22
X TÀI LIỆU THAM KHẢO 23
Trang 4NỘI DUNG CHÍNH
A LÝ THUYẾT
I Định nghĩa Test-driven Development
Test-driven Development (TDD) là một kỹ thuật phát triển phần mềm dựa trên sự lặplại của một chu kỳ phát triển: đầu tiên các nhà phát triển viết một automated test case xácđịnh một cải thiện mong muốn hoặc một chức năng mới, sau đó tạo ra một lượng tối thiểucode để vượt qua test case đó, và cuối cùng cấu trúc lại mã mới với các tiêu chuẩn chấpnhận được
Phát triển dựa trên kiểm thử (Test-Driven Development-TDD) là một phương pháptiếp cận cải tiến để phát triển phần mềm trong đó kết hợp phương pháp Phát triển kiểmthử trước (Test First Development) và phương pháp Điều chỉnh lại mã nguồn(Refactoring) Có quan điểm cho rằng mục tiêu của TDD là đặc tả (specification) chứkhông phải là xác nhận tính đúng đắn (validation) Nói cách khác, đó là một cách để nghĩ
về thiết kế của bạn trước khi viết mã nguồn cho chức năng Một quan điểm khác lại chorằng TDD là một kỹ thuật lập trình Nhưng nhìn chung, mục tiêu của TDD là viết mãnguồn sáng sủa, rõ ràng và có thể chạy được
TDD hoàn toàn thay đổi cách phát triển truyền thống Khi bạn bắt đầu thực hiện mộttính năng mới, câu hỏi đầu tiên đặt ra là liệu thiết kế hiện tại có phải là thiết kế tốt nhấtcho phép bạn thực hiện các chức năng hay không Nếu có, bạn tiến hành thông qua mộtphương pháp Phát triển kiểm thử trước TFD Nếu không, bạn điều chỉnh lại nó một cáchcục bộ để thay đổi riêng phần thiết kế bị ảnh hưởng bởi tính năng mới, cho phép bạn dễdàng bổ thêm các tính năng có thể Kết quả là chất lượng thiết kế của bạn sẽ luôn luônđược nâng cao, do đó sẽ thuận lợi hơn khi làm việc với nó trong tương lai
Trang 5Một giả định cơ bản của TDD là bạn có sẵn một nền tảng (framework) cho kiểm thửmức đơn vị (unit-test) Những lập trình viên phần mềm theo phương pháp Agile thường
sử dụng các công cụ mã nguồn mở thuộc họ xUnit, như JUnit hay PyUnit, mặc dù cáccông cụ thương mại cũng là những lựa chọn khả dĩ Nếu không có những công cụ nhưvậy thì TDD hầu như không thể thực hiện được
Hai nguyên tắc đơn giản cho TDD: Trước tiên, bạn nên viết mã xử lý nghiệp vụ mớichỉ khi mẫu kiểm thử tự động thực hiện không thành công Thứ hai, bạn nên loại bỏ bất
kỳ sự trùng lặp mà bạn tìm thấy Những quy tắc đơn giản:
Bạn thiết kế với mã nguồn mà chúng chạy được và tạo ra kết quả phản hồi giữacác quyết định
Bạn viết các mẫu kiểm thử cho riêng bạn bởi vì bạn không thể chờ đợi 20 lần mỗingày một người nào khác viết thay bạn
Môi trường phát triển của bạn phải cung cấp được kết quả nhanh với những thayđổi nhỏ (ví dụ như bạn cần một trình biên dịch nhanh và chuỗi kiểm thử hồi quy(regression test)
Thiết kế của bạn phải bao gồm những thành phần gắn kết, sự phụ thuộc lẫn nhaunhỏ (loosely coupled) để thực hiện các mẫu kiểm thử dễ dàng hơn (điều này cũnglàm cho quá trình nâng cấp và bảo trì các hệ thống của bạn dễ dàng hơn)
II Tại sao một phần mềm nên phát triển theo hướng TDD?
1 TDD và cách kiểm thử truyền thống
TDD là một kỹ thuật thiết kế với một hiệu ứng phụ là việc đảm bảo toàn bộ mãnguồn của bạn được thực hiện kiểm thử mức đơn vị Tuy nhiên, có những điều còn quantrọng hơn cả việc thực hiện kiểm thử Bạn sẽ vẫn cần xem xét các kỹ thuật kiểm thử khácnhư kiểm thử chấp nhận sản phẩm (acceptance test) hay kiểm thử dò hỏi (investigativetest) theo kiểu Agile Bạn có thể thực hiện nhiều những kiểu kiểm thử này trong dự ánnếu như bạn chọn làm điều đó (và bạn nên làm)
Trang 6Với kiểu kiểm thử truyền thống, một mẫu kiểm thử thành công sẽ tìm ra một hoặcnhiều lỗi Tương tự với TDD, khi một mẫu kiểm thử thất bại thì bạn cũng có sự tiến triểnbởi vì bây giờ bạn biết rằng bạn cần phải giải quyết một số vấn đề Quan trọng hơn, bạn
có một cách đo rõ ràng về sự thành công khi mẫu kiểm thử không thất bại nữa TDD tăngniềm tin về hệ thống của bạn đáp ứng được các yêu cầu được định nghĩa cho nó, và hệthống của bạn đang hoạt động và do đó bạn có thể tiếp tục với một sự tự tin
Như với thử nghiệm truyền thống, hệ thống càng có nhiều rủi ro lớn càng cần phải cónhiều mẫu kiểm thử được thực hiện Với cả hai kiểu kiểm thử truyền thống và TDD bạnkhông phấn đấu cho sự hoàn hảo, thay vào đó bạn kiểm thử tầm quan trọng của hệ thống.Một hiệu ứng phụ thú vị của TDD là bạn đạt được 100% khi kiểm thử độ phủ mã nguồn(coverage test) - mọi dòng mã đều được kiểm thử - điều mà kiểm thử truyền thống khôngbảo đảm dù cho nó khuyến khích điều đó Không có gì ngạc nhiên khi nói rằng TDD làmột kỹ thuật đặc tả (specification technique), với một tác dụng phụ có giá trị là nó đemlại kết quả trong việc kiểm thử mã nguồn tốt hơn đáng kể so với các kỹ thuật truyềnthống
2 Tại sao dùng TDD?
Một lợi thế đáng kể của TDD là nó cho phép bạn thực hiện các bước nhỏ khi viếtphần mềm.Đây là một thực tế mà người ta đã phát huy trong nhiều năm qua bởi vì nómang lại hiệu quả nhiều hơn so với cố gắng viết mã trong những bước lớn Ví dụ, giả sửbạn thêm một số mã nguồn cho chức năng mới, biên dịch, và kiểm thử nó Khả năng rấtlớn là các kiểm thử của bạn sẽ thất bại bởi những lỗi có trong mã nguồn mới Sẽ dễ dànghơn nhiều trong việc tìm kiếm, và sau đó sửa chữa những lỗi đó nếu bạn đã viết thêm haidòng mã mới thay vì hai nghìn dòng
Nhiều người cho rằng các kỹ thuật Agile hoạt động rất ổn với những dự án nhỏ, cầnmột số ít người trong một vài tháng, nhưng chúng không hoạt động đối với những dự ánthực sự lớn hơn Tuy nhiên, điều đó không hoàn toàn đúng Người ta đã đưa ra một bản
Trang 7báo cáo rằng làm việc với một hệ thống Smalltalk sử dụng hoàn toàn phương pháp hướngkiểm thử (test-driven) hết 4 năm với chi phí nhân công 40 man-year, ra kết quả gồm250,000 dòng mã nguồn chức năng và 250,000 dòng mã kiểm thử Có 4000 mẫu kiểmthử chạy dưới 20 phút, còn với bộ mẫu kiểm thử đầy đủ thì cần chạy vài ngày Điều đóchứng tỏ rằng TDD vẫn hoạt động tốt với những dự án có kích thước lớn.
III Chu trình phát triển
Chu trình phát triển của TDD
1 Add a test
Trong phát triển dựa trên kiểm thử, mỗi tính năng mới bắt đầu bằng cách viết mộtkiểm thử (a test) Kiểm thử này chắc chắn phải thất bại vì nó được viết trước khi tínhnăng đã được thực hiện (nếu nó không thất bại, thì hoặc là đề xuất tính năng " mới " đãtồn tại hoặc kiểm thử là khiếm khuyết) Để viết một kiểm thử (a test), các nhà phát triển
Trang 8phải hiểu rõ đặc tả yêu cầu của tính năng này Nhà phát triển có thể thực hiện điều nàythông qua mô hình Use cases và những câu chuyện của người sử dụng bao gồm các yêucầu và điều kiện ngoại lệ, và có thể viết các test trong bất cứ framework kiểm thử nàophù hợp với môi trường phần mềm Điều này có thể dẫn đến sửa đổi một test hiện tại Đây là một tính năng khác biệt của phát triển dựa trên kiểm thử so với kiểm thử đơn vịsau khi các mã được viết: nó làm cho các nhà phát triển tập trung vào các yêu cầu trướckhi viết mã.
2 Run all tests and see if the new one fails
Điều này xác nhận rằng kiểm thử (test) đang làm việc một cách chính xác và rằng cáctest mới không pass nhầm mà không cần bất kỳ code mới nào Bước này cũng kiểm thửchính các test, trong trường hợp tiêu cực: nó bác bỏ khả năng các kiểm thử mới luôn luônpass, và do đó là vô giá trị Các test mới cũng fail vì lý do kỳ vọng Điều này làm tăng sự
tự tin (mặc dù không đảm bảo) mà nó được kiểm thử đúng, và chỉ pass trong trường hợp
dự định
3 Write some code
Bước tiếp theo là viết một số mã tạo ra kiểm thử để pass Mã mới được viết trong giaiđoạn này là không hoàn hảo Điều đó là chấp nhận được vì các bước sau sẽ cải thiện nó.Tại thời điểm này, mục đích duy nhất của các mã được viết là phải vượt qua các test,không có thêm chức năng (và do đó chưa được kiểm tra) nên được dự đoán và "chophép" bất kỳ lúc nào
4 Run tests
Nếu tất cả các test cases đều pass, lập trình viên có thể tự tin rằng code đã đáp ứngđược tất cả các yêu cầu Đây là thời điểm tốt để bắt đầu bước cuối cùng của chu kỳ pháttriển
Trang 95 Refactor code
Tái cấu trúc là quá trình làm thay đổi hiện có, code mà không cần thay đổi hành vibên ngoài của nó Nói cách khác, thay đổi như thế nào mà nó phải là nó, nhưng khôngphải những gì nó làm Mục đích là để cải thiện cấu trúc nội bộ
Các tình huống cần phải cấu trúc lại là:
- Khi có sự trùng lặp
- Khi chúng ta thấy rằng code và/hoặc mục đích của nó không rõ ràng
- Khi chúng ta cảm thấy code có vấn đề (theo cảm tính)
6 Repeat
Bắt đầu với một kiểm thử (a test) mới, chu kỳ sau đó được lặp đi lặp lại để hoàn thiệncác chức năng Kích thước của các bước cần luôn luôn là nhỏ, với ít nhất là 1-10 sửa đổigiữa mỗi lần chạy kiểm thử Nếu mã mới không nhanh chóng đáp ứng một kiểm thử mới,hoặc các kiểm thử khác fail không ngờ tới, các lập trình viên nên lùi lại hoặc trở lại ưutiên cho gỡ lỗi nhiều hơn
IV Thuận lợi khi sử dụng TDD
1 Chất lượng tốt hơn với TDD
a Chất lượng trên nhiều khía cạnh
Bằng chứng là bộ phận đảm bảo chất lượng của thế giới doanh nghiệp của ngày nay , có
xu hướng gán chất lượng với số lỗi được tìm ra sau khi sử dụng phần mềm Một số kháclại coi việc chất lượng là những thứ khác như mức độ mà các phần mềm đáp ứng đượcnhu cầu và mong đợi từ người dùng Một só xem xét không chỉ chất lượng có thể nhìn từbên ngoài mà còn đặc tính bên trong của phần mềm (bên ngoài : chi phí phát triển bảotrì) TDD góp phần cải thiện chất lượng trong tất cả khía cạnh với thiết kế hướng dẫn vàchất lượng theo định hướng bản chất của nó
Rất có thể nhiều lí do cho các lỗi là sự sơ suất trong quá trình tạo sản phẩm, đó là khôngtest xác minh lại các trường hợp đặc biệt mà theo code nó vẫn hoạt động đúng(có thể làkhông chạy test hoặc chạy test một cách cẩu thả) TDD giải quyết vấn đề này bằng cáchđảm bảo rằng có thực tế nếu không có mã code trong hệ thống đó là không yêu cầu và do
đó thực hiện bằng các test TDD hiệu quả là đảm bảo rằng bất cứ điều gì bạn viết một
Trang 10test cho, chất lượng hơn nếu có nhiều hơn các hàm chức năng chúng ta làm thế nàochúng ta thành công , qua các testcase.
Một phần quan trọng của nhiệm vụ đó là vấn để kĩ năng test đó là khả năng lấy cáctestcase cho các trường hợp bình thường , các trường hợp biên, người sử dụng có thể dựđoán được lỗi,… Các TDD có thể hỗ trợ phần này bằng cách cho phép chúng ta tập trungvào các giao diện cho các module, các class, những gì bạn có Bởi những gì không biếtcài đặt như thế nào, chúng ta có thể định vị tốt hơn ngoài việc nghĩ về khuôn khổ chúng
ta chỉ tập trung làm thế nào để code nên xử lívà làm thế nào để các nhà phát triển củakhách hàng có thể , muốn sử dụng nó
Điều quan trọng là trong suốt quá trình phát triển các vấn đề được phát hiện sớm vàchỉnh sửa khi chúng được tìm thấy Thông thường thì các vấn đề lớn xảy ra khi có một
sự hiểu lầm, hiểu sai yêu cầu giữa khách hàng và người lập trình.những vấn đề này có thểtránh được nếu có một cách để xác định những yêu cầu rõ rằng trước khi bắt đầu pháttriển Nhập các test Các test xác định yêu cầu bằng cái cách mà không yêu cầu conngười giải thích về sự thành công hay thất bại Nếu có đủ số lượng test và chúng đượctạo ra trước khi phát triển Chỉ đơn giản là chạy các test và các định thành công hay thấtbại sẽ giúp giải quyết các vấn đề cũ của phát triển phần mềm “Are We Done?” Câu trảlời không phải còn là sự giải thích dài dòng, mà là code có qua tất cả test hay không Saukhi nó qua các test, nghĩa là đã hoàn thành
Giải pháp cho vấn đề có thể như thế là đủ, nhưng nó nhiêù hơn thế Các test được viếttrong quá trình phát triển , có thể chạy và tăng cường bởi đảm bảo chất lượng phầnmềm(QA) với các test Vì code được viết với việc test như là một động lực , cơ sởchính, kết quả code dễ dàng hơn để test Có một cơ sở là bộ test hiện có và code thì nó
dễ hơn để test nên cho cho phép chuyển từ việc phản ứng thụ động sang chủ động hơnbản thân các test là hữu dụng không chỉ trong phát triển ban đầu của phần mềm , nếuchúng được duy trì với việc viết code, chúng có thể được sử dụng để duy trì phần mềm
Ví dụ, nếu một sản phẩn được phát hiện trong quá trình viết code, bước đầu tiên nênđược viết là một test để xác định rõ ràng vấn đề và sau đó, bạn có một test fail, nếu đúng
là có vấn đề Sau đó, test mới này xác định kịch bản mà được xác định trong suốt quátrình phát triển trước đó Nếu bạn làm nhất quán được điều này Các test sẽ phát triểnthành các chương trình được sử dụng trong đời sống thực, làm tăng giá trị của chúng theocấp số nhân Khi thêm một tính năng bạn có thể chạy các bộ test để chắc chắn những mãcode mới không phá vỡ bất kì test nào đã có Nếu sự bao quát của các test là đủ, chạy bộtest và nhận được một kết quả thành công sẽ giảm đi sự lo ngại của bạn Sự phá vỡchức năng hiện tại có thể là vị bạn quá thận trọng, làm bạn chậm chạp hơn Viẹc dùngtest như là cách để lấy lại cân bằng và hướng đi để bạn phát triển chương trình
b Thời gian cho fix lỗi
Trang 11TDD giúp chúng ta tăng tốc độ bằng cách giảm thời gian cần đẻ sửa chữa các lỗi Mộtcảm giác phổ biến là sửa chữa một lỗi sau khi được sản phẩm được sử dụng hai thángmất nhiều thời gian và tiền bạc hơn nhiều so với sửa chữa nó trong cùng với một gnày nóđược giới thiệu Bất cứ điều gì chúng ta có thể làm để giảm thiểu số lõi giới thiệu ở lầnđầu tiên, và để giúp chúng ta tìm thấy những lỗi đó khi đang được làm, đó là các ràngbuộc phải trải qua Tiến hành tesst đầu tiên trong các bước nhỏ để đảm bảo rằng bạnkhông bao giờ phải chạm vào việc fix lỗi TDD giúp chúng ta xây dựng code với chấtlượng kĩ thuật code , những gì chúng ta mong đợi là code dễ dàng để hiểu và để làm việcvới nó Ngay cả những code tốt nhất bằng văn bản
2 Nhu cầu về việc trao đổi để xác định chức năng
Giúp định hình ý tưởng thiết kế hơn là kiểm nghiệm mã chương trình, thực hiện theoTDD sẽ làm sáng tỏ thêm các yêu cầu bài toán, giải tỏa bế tắc trong khi đi tim giải phápphát hiện sớm các vấn đề về thiết kế và tránh được những công việc phải làm lại Chúng
ta xác định đúng bài toán
1 Có thể làm tài liệu cho nhà phát triển
Các nhà phát triển thường thích đọc code và những ví dụ hơn là gặm nhấm tài liệugiải thích các vấn đề kĩ thuật bằng ngôn ngữ phi kỹ thuật TDD làm chính xác nhữngcông việc đó Việc thêm một vài comment trước mỗi test nếu cần, bạn đã có tài liệuhướng dẫn cho các nhà phát triển khác Tất nhiên cần phân biệt tài liệu cho nhà phát triển
và cho người sử dụng Tài liệu cho nhà phát triển cũng cần có hướng dẫn tổng quan,phương pháp luận , quy ước… nữa
2 Các lập trình viên được làm chủ
Các lập trình viên có thể làm mọi thứ trên code của mình mà không sợ ảnh hưởng đến
hệ thống như thế nào miễn là code đấy đảm bảo pass qua các test Không ai dám đảmbảo điều gì với một hệ thống có nhiều nguy cơ, các lập trình viên không cần quan tâmđến điều đó Với mỗi một test hoàn thành chỉ có thể là fail thì chứng tỏ bạn đã phá vỡmột cái gì đó còn nếu pass thì bạn không cần phải làm gì nữa cả
V Hướng phát triển, áp dụng TDD cho các công nghệ phát triển
1 Test_driving với các thành phần web
a Test-driving với Java Servlets
Có 2 đối số HttpServletRequest đại diện yêu cầu phương HTTP và đóng gói các thông
số cần thiết Đối tượng yêu cầu cũng hoạt động như một phương tiện truyền dữ liệu từthành phần yêu cầu xử lý dữ liệu.Đối số thứ 2 là đối tượng HttpServletResponse là cổng