Test-driven development: Difference between revisions

Content deleted Content added
TDD is not about requirements; it's a series of steps for coding
Test-driven development cycle: improve organization and wording
Line 22:
== Test-driven development cycle ==
[[File:TDD Global Lifecycle.png|thumb|A graphical representation of the test-driven development lifecycle]]
The following sequence is 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> amended by Kent Beck's [https://tidyfirst.substack.com/p/canon-tdd Canon TDD article]
 
The followingTDD steps vary somewhat by author in count and description, but are generally as follows. sequenceThese isare 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> amended byand Kent Beck's [https://tidyfirst.substack.com/p/canon-tdd Canon TDD article].
;1. Create a list of tests for the new feature
 
:Given a system & a desired change in behavior, list all the expected variants in the new behavior. “There’s the basic case & then what if this service times out & what if the key isn’t in the database yet &…” The developer can discover these specifications by asking about [[use case]]s and [[user story|user stories]]. A key benefit of test-driven development is that it makes the developer focus on requirements ''before'' writing code. This is in contrast with the usual practice, where unit tests are only written ''after'' code.
;1. CreateList athe listtest of testsscenarios for the new feature
:Given a system & a desired change in behavior, list allList the expected variants in the new behavior. “There’s the basic case & then what -if this service times out & what -if the key isn’t in the database yet &…” The developer can discover these specifications by asking about [[use case]]s and [[user story|user stories]]. A key benefit of test-driven developmentTDD is that it makes the developer focus on requirements ''before'' writing code. This is in contrast with the usual practice, where unit tests are only written ''after'' code.
;2. Add one test from the list
:Write an automated test that passes''would'' pass if the variant in the new behavior is met.
;3. Run all tests. The new test should ''fail'' {{endash}} for ''expected'' reasons
:This shows that new code is actually needed for the desired feature. It validates that the [[test harness]] is working correctly. It rules out the possibility that the new test is flawed and will always pass.
;4. Write the simplest code that passes the new test
:Inelegant orcode and [[hard codecoding]] is acceptable, as long as it passes the test. The code will be honed anyway 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 changes until all pass.
:If any fail, the new code must be revised until they pass. This ensures the new code meets the [[Software requirements|test requirements]] and does not break existing features.
;6. Refactor as needed, usingwhile testsensuring afterall eachtests refactorcontinue to ensure that functionality is preservedpass
: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 helps ensureensures that no existing functionality is broken. Examples of refactoring:
:** moving code to where it most logically belongs
:*Examples of refactoring:
:** removing [[duplicate code]]
:** moving code to where it most logically belongs
:** making [[name]]s [[Self-documenting code|self-documenting]]
:** removing [[duplicate code]]
:** splitting methods into smaller pieces
:** making [[name]]s [[Self-documenting code|self-documenting]]
:** re-arranging [[Inheritance (object-oriented programming)|inheritance hierarchies]]
:** splitting methods into smaller pieces
:** re-arranging [[Inheritance (object-oriented programming)|inheritance hierarchies]]
;Repeat
:Repeat the process, starting at step 2, with each test on the list until all tests are implemented and passing.
:The cycle above is repeated for each new piece of functionality. Tests should be small and incremental, and commits made often. That way, if new code fails some tests, the programmer can simply [[undo]] or revert rather than [[debug]] excessively. When using [[Library (computing)|external libraries]], it is important not to write tests that are so small as to effectively test merely the library itself,<ref name=Newkirk /> unless there is some reason to believe that the library is buggy or not feature-rich enough to serve all the needs of the software under development.
 
Each tests should be small and commits made often. If new code fails some tests, the programmer can [[undo]] or revert rather than [[debug]] excessively.
=== Test-driven work ===
 
Test-driven development has been adopted outside of software development, in both product and service teams, as test-driven work.<ref>Leybourn, E. (2013) ''Directing the Agile Organisation: A Lean Approach to Business Management''. London: IT Governance Publishing: 176-179.</ref> For testing to be successful, it needs to be practiced at the micro and macro levels. Every method in a class, every input data value, log message, and error code, amongst other data points, need to be tested.<ref>{{Cite web |last=Mohan |first=Gayathri |title=Full Stack Testing |url=https://www.thoughtworks.com/en-us/insights/books/full-stack-testing |access-date=2022-09-07 |website=www.thoughtworks.com |language=en-US}}</ref> Similar to TDD, non-software teams develop [[quality control]] (QC) checks (usually manual tests rather than automated tests) for each aspect of the work prior to commencing. These QC checks are then used to inform the design and validate the associated outcomes. The six steps of the TDD sequence are applied with minor semantic changes:
:The cycle above is repeated for each new piece of functionality. Tests should be small and incremental, and commits made often. That way, if new code fails some tests, the programmer can simply [[undo]] or revert rather than [[debug]] excessively. When using [[Library (computing)|external libraries]], it is important not to write tests that are so small as to effectively test merely the library itself,<ref name=Newkirk /> unless there is some reason to believe that the library is buggy or not feature-rich enough to serve all the needs of the software under development.
 
=== Test-driven work ===
 
Test-driven developmentTDD has been adopted outside of software development, in both product and service teams, as '''test-driven work'''.<ref>Leybourn, E. (2013) ''Directing the Agile Organisation: A Lean Approach to Business Management''. London: IT Governance Publishing: 176-179.</ref> For testing to be successful, it needs to be practiced at the micro and macro levels. Every method in a class, every input data value, log message, and error code, amongst other data points, need to be tested.<ref>{{Cite web |last=Mohan |first=Gayathri |title=Full Stack Testing |url=https://www.thoughtworks.com/en-us/insights/books/full-stack-testing |access-date=2022-09-07 |website=www.thoughtworks.com |language=en-US}}</ref> Similar to TDD, non-software teams develop [[quality control]] (QC) checks (usually manual tests rather than automated tests) for each aspect of the work prior to commencing. These QC checks are then used to inform the design and validate the associated outcomes. The six steps of the TDD sequence are applied with minor semantic changes:
# "Add a check" replaces "Add a test"
# "Run all checks" replaces "Run all tests"