- 論壇徽章:
- 0
|
原文鏈接:
http://en.wikipedia.org/wiki/Test-driven_development
Test-driven development
來自 Wikipedia:開放性的百科全書
Test-Driven
Development (TDD)是一種軟件開發(fā)技術(shù)。這種技術(shù)中,在每個很短的周期中首先編寫測試用例(test
cases)覆蓋新的功能和需改進的功能,然后寫必要的實現(xiàn)代碼以通過測試用例,最終用重構(gòu)軟件去適應變化。在實際開發(fā)前寫測試用例的益處是保證能夠根據(jù)
任何變化得到反饋信息。從業(yè)者(practitioners)強調(diào)test-driven
development是一種軟件設計方法,而不僅僅是一種測試方法。
Test-Driven Development
這個概念始于二十世紀晚期,是一個和測試先行編程概念(the test-first
programming)相關(guān)的概念,但是最近它(譯者注:“它”指Test-Driven Development)憑自己的能力得到了廣泛的關(guān)注。
這個概念也可以結(jié)合其它技術(shù)用于改進和去除以前用其它方式開發(fā)的軟件的缺陷。
目錄
1.依賴(原文:requirements)
2.Test-Driven Development周期
2.1 1.添加一個test
2.2 2.運行所有的test,新的test要失敗(原文:Run all tests and see the new one fail)
2.3 3.寫一些代碼
2.4 4.運行自動測試,使所有的test都成功(原文:Run the automated tests and see them succeed)
2.5 5.代碼重構(gòu)
2.6 重復以上步驟
3.開發(fā)風格
4.優(yōu)點
5.局限性
6.代碼可見
7.偽造、仿造和集成測試(原文:Fakes, mocks and integration tests)
8.參考
9.附加參考
10.一些鏈接
1.依賴(原文:requirements)
Test-driven
development依賴于自動單元測試(an automated unit test)。自動單元測試(an automated unit
test)要在寫代碼之前先寫,其中定義了代碼的需求。這些測試中包含了非真即假的斷言(assertions)。
運行這些測試可以快速確定代碼展開的行為以及重構(gòu)代碼的正確性;趚Unit概念(請查看單元測試框架列表)的測試框架提供了制作和運行一系列自動測試用例的機制。
2.Test-Driven Development周期
以下周期的順序參考Test-Driven Development by Example這本書。此書是用現(xiàn)代手法闡述Test-Driven Development這一概念的權(quán)威作品。
2.1 添加一個test
在test-driven
development中,一切新功能的開發(fā)從寫test開始。由于功能沒有被實現(xiàn),所以這一步中所寫的test必然會失敗。開發(fā)人員為了確保清楚理解各
個規(guī)格和新功能中所有的需求,可以通過分析用例(use cases)和user stories全面掌握需求和異常情況。
這也說明了有可能保留或修改現(xiàn)有的test。這一特性是Test-driven development和完成代碼后的單元測試一個微妙卻重要的區(qū)別,它使你將精力集中在代碼前的需求上。
2.2 運行所有的test,新的test要失敗(原文:Run all tests and see the new one fail)
這里保證test工作正常,而且新的test在缺少實現(xiàn)代碼的情況下沒有失誤的通過測試。
新的test預期應該失敗。這里以否定形式測試test本身(This step tests the test itself, in the
negative)。從某種程度上講,“否定測試”(a negative
test)和測試人員(testers)類似,當一個特性應該失敗時確保它失敗,例如錯誤的數(shù)據(jù)輸入。
“肯定測試”(positive
tests)保證代碼按照預期的設定工作,例如正確的數(shù)據(jù)輸入,它(譯者注:指“肯定測試”)和“否定測試”(a negative
test)配合使用。(保證它工作,然后改變它使它中斷并保證它中斷)(原文:"Make sure it works, then change
one thing to make it break and make sure it breaks.")
整個一系列單元測試都服務于此需求,通過檢查每一個test以保證“否定測試”按照預期的原因失敗。
這一技術(shù)避免了test總是通過成功而使test失去價值這一弊病。第一次運行新的test,看著它失敗,這是一個至關(guān)重要的健全的測試。
2.3 寫一些代碼
寫一些代碼讓test成功通過。新寫的代碼不完美,甚至可能用不優(yōu)雅的方式通過了測試。應該接受這個情況,因為后面的步驟中會對代碼進行改進和打磨。
2.4 運行自動測試,使所有的test都成功(原文:Run the automated tests and see them succeed)
現(xiàn)在如果所有的測試用例(test cases)都成功的通過,程序員應改相信代碼設計到了所有應測得需求。這是到達終點的好的起點。
2.5 代碼重構(gòu)
現(xiàn)在有必要使代碼更清晰。開發(fā)人員可以通過重新運行測試用例(test
cases)以保證重構(gòu)沒有對任何原有功能造成破壞。去除冗余是任何一個軟件設計中的重要方面。(原文:The concept of
removing duplication is an important aspect of any software design.)所以,要去除測試代碼(test code)和產(chǎn)品代碼(production code)中的任何冗余。例如去除冗余的幻數(shù)(magic numbers)和字符串(strings),從而使2.3中寫的代碼通過。(原文:for example magic numbers or strings that were repeated in both, in order to make the test pass in step 3.)
2.6 重復以上步驟
開始一個新的test并重復循環(huán)周期以推進功能的開發(fā)。如果開發(fā)人員愿意的話,可以調(diào)小開發(fā)的步伐,或者增大步伐如果他/她很有信心的話。如果適合test的代碼不能很快地通過,那么以前的步伐可能過大。
當使用附加的庫時,很重要的一點是不要用過小的步伐而導致僅僅測試了庫本身(原文:When using external libraries it
is important not to make increments that are so small as to be
effectively merely testing the library itself)。除非有一些原因是你相信庫本身存在bug或者不足以服務于所有的需求(原文:unless there is some reason to
believe that the library is buggy or is not sufficiently feature
complete to serve all the needs of the main program being written.)。
3.開發(fā)風格
很多方面都可以使用test-driven development,例如"kiss it simple,stupid"(KISS)和"You Ain't Gonna Need It"(YANGI)。集中精力寫必要的代碼以使其通過test,設計會越來越清晰,因此常常能用其它方法實現(xiàn)。(一些人還建議使用"Fake it, till you make it"這個原則)。為
了運用先進的設計概念(像Design Pattern),寫test時會運用這種模式。(To achieve some advanced
design concept (such as a Design Pattern),tests are written that will
generate that design.)代碼可能會比目標代碼要簡潔,但是仍然通過所有的test.起初這可能會令人不安,但是卻讓開發(fā)人員能夠集中精力在重要的事情上。
Test-driven development 要求開發(fā)人員首先使測試用例(test cases)失敗。這確保test確實在工作并能捕捉一個錯誤。之后,正常的循環(huán)周期開始了。"紅/綠/重構(gòu)"已經(jīng)成為了Test-Driven-Development 格言("Test-Driven Development Mantra"),其中“紅”表示失敗而“綠”表示通過。
Test-driven development不斷地重復著“失敗”、“通過”、“重構(gòu)”的步驟。得到預期的測試結(jié)果鞏固了編程者頭腦中的代碼模型、增加了自信、提高生產(chǎn)能力。
先進的實踐使test-driven development發(fā)展出了Acceptance Test-driven development[ATDD]。這種技術(shù)中,客戶制定的標準自動進入acceptance tests,它們驅(qū)動傳統(tǒng)的
單元測試驅(qū)動開發(fā)[UTDD]過程(the traditional unit test-driven development UTDD]process.) 這個過程保證客戶用自動機制決定軟件是否迎合了需求。用ATDD這種技術(shù),現(xiàn)在開發(fā)團隊有了一個明確的目標,那就是acceptance tests,它使開發(fā)團隊始終致力于從user story得來的客戶的真正的需求。
4.優(yōu)點
最近的研究表明使用TDD意味著寫更多的測試,而且編程者寫更多的測試意在提高生產(chǎn)力。關(guān)于代碼質(zhì)量的猜側(cè)以及TDD和生產(chǎn)力之間的直接聯(lián)系是不能確定的。(原文:Hypotheses relating to code quality and a more direct correlation between TDD and productivity were inconclusive.)
完全使用TDD開發(fā)一個新工程的編程者說他們幾乎不需要測試人員。(原文:Programmers using pure TDD on new
("greenfield") projects report they only rarely feel the need to invoke
a debugger. )
結(jié)合版本控制系統(tǒng)(a Version control system),當測試沒有通過時,可以恢復為上一個通過測試的代碼版本,這可能比調(diào)試的生產(chǎn)率要更高。
Test-driven development 幫助軟件開發(fā)的更好、更快。它提供的不僅僅是對于對錯的簡單驗證,更驅(qū)動著如何設計程序。當精力首先集中在測試用例時,你必須首先想象客戶如何使用這些功能。所以,編程者只關(guān)心接口而不是實現(xiàn)類。這一優(yōu)點是對Design by Contract的補充,因為通過測試用例去實現(xiàn)代碼而不是通過數(shù)學斷言或預想。
test-driven development有能力在必要時使用小步伐進行開發(fā)。它允許編程者對手頭的工作集中精力,因為首要的目標是使測試通過。異常情況的用例和錯誤的捕獲不是在最開始進行的。對于創(chuàng)造額外環(huán)境的測試用例屬于單獨的應用(原文:Tests to create these extraneous circumstances are implemented separately.)。另一個優(yōu)點是:當使用得當,test-driven development 保證所有的代碼都被測試用例覆蓋。這可以使編程者以及再次開發(fā)者很大程度上信任代碼。
這是真的,單元測試使更多的代碼需要TDD,因為它使整體實現(xiàn)時間縮短。大量的測試限制了代碼的缺陷。早期和頻繁的測試幫助我們在開發(fā)周期的早期發(fā)現(xiàn)缺陷,并阻止這些缺陷成為根深蒂固或代價昂貴的問題(原文:The early and frequent nature of the tests helps to
catch defects early in the development cycle, preventing them from becoming endemic and expensive problems.)。早期消除缺陷經(jīng)常能避免以后單調(diào)乏味的調(diào)試(原文:Eliminating defects early in the
process usually avoids lengthy and tedious debugging later in the project.)。
TDD帶來的是模塊化、更靈活、可擴展的代碼。因為方法論要求開發(fā)人員要求依據(jù)小單元來考慮軟件,這些小單元可以獨立生成和進行測試,而且以后進行集成到一起。這帶來的是更小、更集中的類,更小的耦合,更干凈的接口!癕ock Object design pattern”也致力于代碼的整體模塊化,這個模式的要求是:所寫的代碼可以使模塊從用于單元測試的mock版本到用于開發(fā)的“真正的”版本方便的切換。
5.局限性
TDD在某些情況下很難適用。例如圖形用戶接口、數(shù)據(jù)庫相關(guān)的系統(tǒng),因為這些系統(tǒng)包含了復雜的輸入、輸出,沒有可以進行單元測試和重構(gòu)的孤立的單元(原文:where systems with complex input and output were not designed for isolated unit testing or refactoring.)。
6.代碼可見
存在三種測試代碼:白盒測試、黑盒測試、玻璃盒測試。黑盒測試測試的是接口的邊界值。因為能保證軟件的模塊性并強行側(cè)重于模塊接口,所以幾乎所有的單元測試都由黑盒測試組成。當測試可以觀察并改變屬于軟件的狀態(tài)時,我們用白盒測試(White box testing occurs when your tests can both observe and mutate state belonging to the software under test. )。這些測試方式被強烈抵制,因為測試到的一些微小的bug很可能由測試用例本身存在的bug導致。玻璃盒測試用于僅僅觀察但不改變產(chǎn)品軟件的狀態(tài)。玻璃盒測試包括驗證一個方法在硬件層次的輸出。例如,驗證跳躍表(a skip-list)的鏈接的設置是否合適,對于跳躍表的成功和領(lǐng)錯誤實現(xiàn)是至關(guān)重要。測試包中的代碼能夠清晰的訪問所測試的代碼。幾乎所有可以想象的用例中,這樣的訪問涉及到了公開接口、程序和調(diào)用的方法!癿ock”對象的使用保證了不觸及“隱藏”信息,保證了測試的獨立性(原文:The use of "mock objects" ensures information hiding remains intact, guaranteeing a total separation of concerns.)。
用于TDD的單元測試代碼幾乎從來不會放在同一個工程或要測的模塊中(原文:Unit test code for TDD is almost never written within the same project or
module as the code being tested.)。測試代碼會放到一個獨立的模塊或庫中,這樣產(chǎn)品代碼可以保持原樣。把TDD代碼放到同一個模塊(譯者注:指要測試的模塊)中會從根本上改變產(chǎn)品代碼。分情況編譯會帶來微小的bug產(chǎn)生。(譯者認為這句話的意思是:如果將測試代碼和產(chǎn)品代碼放在一起,然后分情況編譯以區(qū)別它們?nèi)匀粫䦷硇〉腷ug)
有人會說,嚴格的黑盒測試是不會訪問私有的數(shù)據(jù)和方法的。這是有意的(原文:This is intentional);隨著軟件的一步步發(fā)展,你會發(fā)現(xiàn)一個類的實現(xiàn)從根本上改變了。
記住,test-driven development中決定性的一步是重構(gòu)。重構(gòu)會引入變化:對私有方法的添加或刪除,或是改變現(xiàn)有方法的類型。這些變化是不應該破壞現(xiàn)有的測試的。
使用玻璃盒測試的單元測試代碼和產(chǎn)品代碼具有高耦合性;改變一個類或模塊的實現(xiàn)意味著也必須更新或丟棄現(xiàn)有的代碼,而這是永遠都不應該發(fā)生的事情。因為這個原因,使用玻璃盒測試的幾率應降到最低,而白盒測試在test-driven development 中則永遠不要使用。
無論如何,部署問題應該有其思想(原文:In all cases, thought must be given to the question of deployment.)。最好的方法是開發(fā)你的軟件,那么你就有三個主要的部件。第一個主要的部件是應用框架自身的單元測試器。第二個產(chǎn)品邏輯的主要入口模塊。這些模塊將鏈接(最好是動態(tài)鏈接)到一至多個庫上,每個庫實現(xiàn)了一些或所有的業(yè)務邏輯。這能保證模塊整體和徹底的可部署性(原文:This guarantees total modularity and is thoroughly deployable.)。
7.偽造、仿造和集成測試(原文:Fakes, mocks and integration tests)
單元測試得以其名是因為它們測試的是代碼的一個單元,而不管你的代碼中有上百個單元測試或只有5個。在一個程序中,一個測試包是永遠都不應該跨越模塊的。這種做法的風險是引入了大范圍的延遲,而更糟糕的或許是,它無意間將你的單元測試變成了集成測試。后者尤為嚴重,因為在相互關(guān)聯(lián)的模塊組成的鏈中,如果任何模塊失敗了,你的測試就會失敗,并且沒有任何信息表明在哪里、為什么失敗。這擊毀了單元測試的目的。
當開發(fā)中的代碼依賴于數(shù)據(jù)庫或web服務,或者其它的外部程序和服務時,好像就會出現(xiàn)一個問題。然而,這不是一個問題,而是一個設計更多模塊的可能性和驅(qū)動力,這些模塊中有更具可測試性,更具可重用性的代碼。需要下面兩個步驟:
(1)當最終的設計中需要外部的訪問時,需要定義接口去規(guī)定合理的訪問。
(2)實現(xiàn)接口有兩種方式,一種是實際地去訪問外部程序,另一種是偽造或仿造對象(原文:and the other is a fake or mock object)。偽造對象(fake object)需要稍多的設置,不僅僅向追蹤日志(原文:a trace-log)或控制臺增加一句“保存Person對象”。偽造對象(fake object) 也被稱為存根對象(原文:stub objects)。仿造對象(mock object)的不同在于它包含可以使自身不能通過測試的斷言(assertions),例如包含了不合法的用戶名和其它數(shù)據(jù)。仿造對象和偽造對象方法常常返回測試程序所依賴相同的、現(xiàn)實的數(shù)據(jù),而這些數(shù)據(jù)看起來就像來自數(shù)據(jù)庫或用戶一樣。
這個方法的缺點是,在TDD進程中,實際的數(shù)據(jù)庫或其它訪問代碼永遠都無法被測到。我們必須避免一個疏忽:實例化前面提到接口(用于測試驅(qū)動的代碼)時,需要其它的測試。(原文:other tests are needed that instantiate the test-driven code with
its 'real' implementations of the interfaces discussed above. )。多數(shù)開發(fā)者發(fā)現(xiàn)把這些測試同TDD單元測試分開,然后再進行集成測試時參考它們是很有用的事情。這些測試會存在的越來越少,較單元測試來講運行地也少。不過,仍然可以用相同的測試框架,例如 xUnit去實現(xiàn)。
集成測試會改變持久化存儲或數(shù)據(jù)庫,所以應該慎用,使其在任何測試失敗的情況下都可以保持可重復使用。要做到這一點,可以結(jié)合下面的相關(guān)技術(shù):
1。將TearDown方法集成到測試框架中。
2。用try..catch...finally塊進行合理的異常處理
3。當自動事務中包含了寫、讀、刪除操作時,使用數(shù)據(jù)庫事務。
jMock等現(xiàn)有框架使生成和使用偽造對象(mock objects)更容易。
8.參考
1. a b Newkirk, JW and Vorontsov, AA. Test-Driven Development in Microsoft .NET, Microsoft Press, 2004.
2. Feathers, M. Working Effectively with Legacy Code, Prentice Hall, 2004
3. a b Beck, K. Test-Driven Development by Example, Addison Wesley, 2003
4. Erdogmus, Hakan; Morisio, Torchiano. On the Effectiveness of
Test-first Approach to Programming. Proceedings of the IEEE
Transactions on Software Engineering, 31(1). January 2005. (NRC 47445).
Retrieved on 2008-01-14. “We found that test-first students on average
wrote more tests and, in turn, students who wrote more tests tended to
be more productive.”
5. Proffitt, Jacob. TDD Proven Effective!
Or is it?. Retrieved on 2008-02-21. “So TDD's relationship to quality
is problematic at best. Its relationship to productivity is more
interesting. I hope there's a follow-up study because the productivity
numbers simply don't add up very well to me. There is an undeniable
correlation between productivity and the number of tests, but that
correlation is actually stronger in the non-TDD group (which had a
single outlier compared to roughly half of the TDD group being outside
the 95% band).”
6. Clark, Mike. Test-Driven Development with
JUnit Workshop. Clarkware Consulting, Inc.. Retrieved on 2007-11-01.
“In fact, test-driven development actually helps you meet your
deadlines by eliminating debugging time, minimizing design speculation
and re-work, and reducing the cost and fear of changing working code.”
7. Llopis, Noel (20 February 2005). Stepping Through the Looking
Glass: Test-Driven Game Development (Part 1). Games from Within.
Retrieved on 2007-11-01. “Comparing [TDD] to the non-test-driven
development approach, you're replacing all the mental checking and
debugger stepping with code that verifies that your program does
exactly what you intended it to do.”
8. Muller, Matthias M.;
Padberg, Frank. About the Return on Investment of Test-Driven
Development (PDF) 6. Universitat Karlsruhe, Germany. Retrieved on
2007-11-01.
9.附加參考
1. ^ a b Newkirk, JW and Vorontsov, AA. Test-Driven Development in Microsoft .NET, Microsoft Press, 2004.
2. ^ Feathers, M. Working Effectively with Legacy Code, Prentice Hall, 2004
3. ^ a b Beck, K. Test-Driven Development by Example, Addison Wesley, 2003
4. ^ Erdogmus, Hakan; Morisio, Torchiano. On the Effectiveness of
Test-first Approach to Programming. Proceedings of the IEEE
Transactions on Software Engineering, 31(1). January 2005. (NRC 47445).
Retrieved on 2008-01-14. “We found that test-first students on average
wrote more tests and, in turn, students who wrote more tests tended to
be more productive.”
5. ^ Proffitt, Jacob. TDD Proven Effective!
Or is it?. Retrieved on 2008-02-21. “So TDD's relationship to quality
is problematic at best. Its relationship to productivity is more
interesting. I hope there's a follow-up study because the productivity
numbers simply don't add up very well to me. There is an undeniable
correlation between productivity and the number of tests, but that
correlation is actually stronger in the non-TDD group (which had a
single outlier compared to roughly half of the TDD group being outside
the 95% band).”
6. ^ Clark, Mike. Test-Driven Development with
JUnit Workshop. Clarkware Consulting, Inc.. Retrieved on 2007-11-01.
“In fact, test-driven development actually helps you meet your
deadlines by eliminating debugging time, minimizing design speculation
and re-work, and reducing the cost and fear of changing working code.”
7. ^ Llopis, Noel (20 February 2005). Stepping Through the Looking
Glass: Test-Driven Game Development (Part 1). Games from Within.
Retrieved on 2007-11-01. “Comparing [TDD] to the non-test-driven
development approach, you're replacing all the mental checking and
debugger stepping with code that verifies that your program does
exactly what you intended it to do.”
8. ^ Muller, Matthias M.;
Padberg, Frank. About the Return on Investment of Test-Driven
Development (PDF) 6. Universitat Karlsruhe, Germany. Retrieved on
2007-11-01.
10.一些鏈接
* Concordion acceptance testing framework for Java
* Typemock is a powerful and controversial mocking framework for .NET
* The Various Meanings of TDD
* Three Rules of TDD
* Extreme perl - Unit testing
* Write Maintainable Unit Tests That Will Save You Time And Tears
* Improving Application Quality Using Test-Driven Development by Craig
Murphy. This article provides an introduction to Test-Driven
Development with concrete examples using NUnit
* testdriven.com on-line test-driven development community
* Acceptance Test Driven Development
* Test-driven Development using NUnit tutorial (also Java version available)
* c2.com Test-driven development from WikiWikiWeb
* Brief explanation of the Qualities of an Ideal Test
* team test development A non-programmer driven approach towards test driven development.
* Test Driven Development with Visual Studio 2005 Team System - Doug Seven, 3/10/2006
* TDD Anti-Patterns Common mistakes and mishaps when starting out with TDD... a catalog of how to NOT do TDD.
* Introduction to Test-Driven Design (TDD)
* XP Episode By Bob Martin and Bob Koss
* jMock
* Mocking the Embedded World is an article about adapting the test
driven development approach to the embedded software development world
with tools suggestions and a case study.
* Test Driven Development lessons learned
* The Basics of Test Driven Database Design - Max Guernsey, III, 1/26/2008
* Test Driven Development in .NET example for TDD in Visual Studio and
.NET including WatiN test framework for web applications
原文鏈接:
http://en.wikipedia.org/wiki/Test-driven_development
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u2/79394/showart_1348882.html |
|