Content deleted Content added
Tags: Reverted Mobile edit Mobile web edit |
Jnestorius (talk | contribs) |
||
(40 intermediate revisions by 26 users not shown) | |||
Line 1:
{{
{{Software development process}}
'''Test-driven development''' ('''TDD''') is a way of writing [[source code|code]] that involves writing an [[test automation|automated]] [[unit testing|unit-level]] [[Test case (software)|test case]] that fails, then writing just enough code to make the test pass, then [[refactoring]] both the test code and the production code, then repeating with another new test case.
Alternative approaches to writing automated tests is to write all of the production code before starting on the test code or to write all of the test code before starting on the production code. With TDD, both are written together, therefore shortening debugging time necessities.<ref>{{Cite journal |last1=Parsa |first1=Saeed |last2=Zakeri-Nasrabadi |first2=Morteza |last3=Turhan |first3=Burak |date=2025-01-01 |title=Testability-driven development: An improvement to the TDD efficiency |url=https://www.sciencedirect.com/science/article/pii/S0920548924000461 |journal=Computer Standards & Interfaces |volume=91 |pages=103877 |doi=10.1016/j.csi.2024.103877 |issn=0920-5489|url-access=subscription }}</ref>
TDD is related to the test-first programming concepts of [[extreme programming]], begun in 1999,<ref name="Cworld92">{{cite web |url=http://www.computerworld.com/softwaretopics/software/appdev/story/0,10801,66192,00.html |title=Extreme Programming |author=Lee Copeland |date=December 2001 |publisher=Computerworld |access-date=January 11, 2011 |archive-url=https://web.archive.org/web/20110605060209/http://www.computerworld.com/s/article/66192/Extreme_Programming?taxonomyId=063 |archive-date=June 5, 2011 |url-status=dead }}</ref> but more recently has created more general interest in its own right.<ref name=Newkirk>Newkirk, JW and Vorontsov, AA. ''Test-Driven Development in Microsoft .NET'', Microsoft Press, 2004.</ref>
Line 16:
| text = The original description of TDD was in an ancient book about programming. It said you take the input tape, manually type in the output tape you expect, then program until the actual output tape matches the expected output. After I'd written the first xUnit framework in [[Smalltalk]] I remembered reading this and tried it out. That was the origin of TDD for me. When describing TDD to older programmers, I often hear, "Of course. How else could you program?" Therefore I refer to my role as "rediscovering" TDD.
| author = [[Kent Beck]]
| title =
| source = "Why does Kent Beck refer to the 'rediscovery' of test-driven development? What's the history of test-driven development before Kent Beck's rediscovery?"<ref>{{cite web|url=http://www.quora.com/Why-does-Kent-Beck-refer-to-the-rediscovery-of-test-driven-development |title=Why does Kent Beck refer to the "rediscovery" of test-driven development? |author=Kent Beck | date=May 11, 2012 |access-date=December 1, 2014}}</ref>
}}
Line 23:
[[File:TDD Global Lifecycle.png|thumb|A graphical representation of the test-driven development lifecycle]]
The TDD steps vary somewhat by author in count and description, but are generally as follows. These are based on the book ''Test-Driven Development by Example'',<ref name=Beck>{{cite book |last=Beck| first=Kent |title=Test-Driven Development by Example |publisher=Addison Wesley |___location=Vaseem |date=2002-11-08 |isbn=978-0-321-14653-3}}</ref> and Kent Beck's
;1. List scenarios for the new feature
Line 34:
:Inelegant code and [[hard coding]] is acceptable. The code will be honed in Step 6. No code should be added beyond the tested functionality.
;5. All tests should now pass
:If any fail, fix failing tests with minimal
;6. Refactor as needed while ensuring all tests continue to pass
:Code is [[Code refactoring|refactored]] for [[Code readability|readability]] and maintainability. In particular, hard-coded test data should be removed from the production code. Running the test suite after each refactor ensures that no existing functionality is broken. Examples of refactoring:
:* moving code to where it most logically belongs
:* removing [[duplicate code]]
:* making [[
:* splitting methods into smaller pieces
:* re-arranging [[Inheritance (object-oriented programming)|inheritance hierarchies]]
Line 72 ⟶ 69:
===Code visibility===
{{Main|Unit_testing#Code_Visibility}}
In test-driven development, writing tests before implementation raises questions about testing [[access modifiers|private methods]] versus testing only through [[Interface (computing)|public interfaces]]. This choice affects the design of both test code and production code.
When code under development relies on a database, a web service, or any other external process or service, enforcing a unit-testable separation is also an opportunity and a driving force to design more modular, more testable and more reusable code.<ref>{{cite book |title=Refactoring - Improving the design of existing code |last=Fowler |first=Martin |year=1999 |publisher=Addison Wesley Longman, Inc. |___location=Boston |isbn=0-201-48567-2 |url=https://archive.org/details/isbn_9780201485677 }}</ref> Two steps are necessary:▼
===Test isolation===
Test-driven development relies primarily on [[unit testing|unit tests]] for its rapid red-green-refactor cycle. These tests execute quickly by avoiding process boundaries, network connections, or external dependencies. While TDD practitioners also write [[integration testing|integration tests]] to verify component interactions, these slower tests are kept separate from the more frequent unit test runs. Testing multiple integrated modules together also makes it more difficult to identify the source of failures.
▲When code under development relies on
Since test doubles don't prove the connection to real external components, TDD practitioners supplement unit tests with [[integration testing]] at appropriate levels. To keep execution faster and more reliable, testing is maximized at the unit level while minimizing slower tests at higher levels.
===Keep the unit small===
Line 155 ⟶ 104:
* Dependencies between test cases. A test suite where test cases are dependent upon each other is brittle and complex. Execution order should not be presumed. Basic refactoring of the initial test cases or structure of the UUT causes a spiral of increasingly pervasive impacts in associated tests.
* Interdependent tests. Interdependent tests can cause cascading false negatives. A failure in an early test case breaks a later test case even if no actual fault exists in the UUT, increasing defect analysis and debug efforts.
* Testing precise execution
* Building "all-knowing oracles". An oracle that inspects more than necessary is more expensive and brittle over time. This very common error is dangerous because it causes a subtle but pervasive time sink across the complex project.<ref name="pathfindersolns.com">{{YouTube| id=0BWSms3J40Y| title=Test-Driven Development (TDD) for Complex Systems Introduction}} by Pathfinder Solutions</ref>{{Clarify|reason=needs better explanation, what is an all-knowing oracle? needs better tone, more factual|date=February 2022}}
* Testing implementation details.
Line 201 ⟶ 150:
Creating and managing the [[Software architecture|architecture]] of test software within a complex system is just as important as the core product architecture. Test drivers interact with the UUT, [[test double]]s and the unit test framework.<ref name="Pathfinder Solutions" />
== Advantages and Disadvantages
=== Advantages ===
Line 209 ⟶ 158:
# '''Comprehensive Test Coverage''': TDD ensures that all new code is covered by at least one test, leading to more robust software.
# '''Enhanced Confidence in Code''': Developers gain greater confidence in the code's reliability and functionality.
# '''Enhanced Confidence in Tests''': As the tests are known to be failing without the proper implementation, we know that the tests actually tests the implementation correctly.
# '''Well-Documented Code''': The process naturally results in well-documented code, as each test clarifies the purpose of the code it tests.
# '''Requirement Clarity''': TDD encourages a clear understanding of requirements before coding begins.
Line 223 ⟶ 173:
# '''Increased Code Volume''': Implementing TDD can result in a larger codebase as tests add to the total amount of code written.
# '''False Security from Tests''': A large number of passing tests can sometimes give a misleading sense of security regarding the code's robustness.<ref>{{Cite journal |last1=Parsa |first1=Saeed |last2=Zakeri-Nasrabadi |first2=Morteza |last3=Turhan |first3=Burak |date=2025-01-01 |title=Testability-driven development: An improvement to the TDD efficiency |url=https://www.sciencedirect.com/science/article/pii/S0920548924000461 |journal=Computer Standards & Interfaces |volume=91 |pages=103877 |doi=10.1016/j.csi.2024.103877 |issn=0920-5489|url-access=subscription }}</ref>
# '''Maintenance Overheads''': Maintaining a large suite of tests can add overhead to the development process.
# '''Time-Consuming Test Processes''': Writing and maintaining tests can be time-consuming.
# '''Testing Environment Set-Up''': TDD requires setting up and maintaining a suitable testing environment.
# '''Learning Curve''': It takes time and effort to become proficient in TDD practices.
# '''Overcomplication''':
# '''Neglect of Overall Design''': Focusing too narrowly on passing tests can sometimes lead to neglect of the bigger picture in software design.
=== Benefits ===
Line 291 ⟶ 240:
Because no more code is written than necessary to pass a failing test case, automated tests tend to cover every code path. For example, for a TDD developer to add an <code>else</code> branch to an existing <code>if</code> statement, the developer would first have to write a failing test case that motivates the branch. As a result, the automated tests resulting from TDD tend to be very thorough: they detect any unexpected changes in the code's behaviour. This detects problems that can arise where a change later in the development cycle unexpectedly alters other functionality.
Madeyski<ref name="Madeyski">Madeyski, L. "Test-Driven Development - An Empirical Evaluation of Agile Practice", Springer, 2010, {{ISBN|978-3-642-04287-4}}, pp. 1-245. DOI: 978-3-642-04288-1</ref> provided empirical evidence (via a series of laboratory experiments with over 200 developers) regarding the superiority of the TDD practice over the traditional Test-Last approach or testing for correctness approach, with respect to the lower coupling between objects (CBO). The mean effect size represents a medium (but close to large) effect on the basis of meta-analysis of the performed experiments which is a substantial finding. It suggests a better modularization (i.e., a more modular design), easier reuse and testing of the developed software products due to the TDD programming practice.<ref name="Madeyski" /> Madeyski also measured the effect of the TDD practice on unit tests using branch coverage (BC) and mutation score indicator (MSI),<ref>[http://madeyski.e-informatyka.pl/download/Madeyski10c.pdf The impact of Test-First programming on branch coverage and mutation score indicator of unit tests: An experiment. ] by L. Madeyski ''Information & Software Technology 52(2): 169-184 (2010)''</ref><ref>[http://madeyski.e-informatyka.pl/download/Madeyski07.pdf On the Effects of Pair Programming on Thoroughness and Fault-Finding Effectiveness of Unit Tests] by L. Madeyski ''PROFES 2007: 207-221''</ref><ref>[http://madeyski.e-informatyka.pl/download/Madeyski08.pdf Impact of pair programming on thoroughness and fault detection effectiveness of unit test suites.] by L. Madeyski ''Software Process: Improvement and Practice 13(3): 281-295 (2008)''</ref> which are indicators of the thoroughness and the fault detection effectiveness of unit tests, respectively. The effect size of TDD on branch coverage was medium in size and therefore is considered substantive effect.<ref name="Madeyski" /> These findings have been subsequently confirmed by further, smaller experimental evaluations of TDD.<ref name="Pančur">M. Pančur and M. Ciglarič, "Impact of test-driven development on productivity, code and tests: A controlled experiment", Information and Software Technology, 2011, vol. 53, no. 6, pp. 557–573, DOI: 10.1016/j.infsof.2011.02.002</ref><ref name="Fucci">D. Fucci, H. Erdogmus, B. Turhan, M. Oivo, and N. Juristo, "A dissection of the test-driven development process: does it really matter to test-first or to test-last?", IEEE Transactions on Software Engineering, 2017, vol. 43, no. 7, pp. 597–614, DOI: 10.1109/TSE.2016.2616877</ref><ref name="Tosun">A. Tosun, O. Dieste Tubio, D. Fucci, S. Vegas, B. Turhan, H. Erdogmus, A. Santos, M. Oivo, K. Toro, J. Jarvinen, and N. Juristo, "An industry experiment on the effects of test-driven development on external quality and productivity", Empirical Software Engineering, 2016, vol. 22, pp. 1–43, DOI: 10.1007/s10664-016-9490-0</ref><ref name="Papis">B. Papis, K. Grochowski, K. Subzda and K. Sijko, [https://ieeexplore.ieee.org/document/9207972 "Experimental evaluation of test-driven development with interns working on a real industrial project"], IEEE Transactions on Software Engineering, 2020, DOI: 10.1109/TSE.2020.3027522</ref>
=== Psychological benefits to programmer ===
Line 314 ⟶ 263:
| url=https://www.simple-talk.com/dotnet/.net-framework/are-unit-tests-overused/
| title=Are Unit Tests Overused?
| work=Simple Talk
| publisher=Simple-talk.com
| date=2012-10-19 |access-date=2014-03-25}}</ref>
Line 343 ⟶ 293:
== Conference ==
First TDD Conference was held during July 2021.<ref>{{cite web|last=Bunardzic|first=Alex|title=First International Test Driven Development (TDD) Conference|url=https://tddconference.github.io/|access-date=2021-07-20|website=TDD Conference|language=en}}</ref> Conferences were recorded on [[YouTube]]<ref>{{Citation|title=First International TDD Conference - Saturday July 10, 2021| date=10 July 2021 |url=https://www.youtube.com/watch?v=-_noEVCR__I |archive-url=https://ghostarchive.org/varchive/youtube/20211221/-_noEVCR__I |archive-date=2021-12-21 |url-status=live|language=en|access-date=2021-07-20}}{{cbignore}}</ref>
== See also ==
Line 360 ⟶ 310:
* [[Self-testing code]]
* [[Software testing]]
* [[Transformation Priority Premise]]
* [[Unit testing]]
|