Test Driven Developm ent Brian Nielsen Arne Skou bnielsen@cs.aau.dk ask@cs.aau.dk
TDD D fi ifi TDD Definifion “Test-driven Development is a programming practice that instructs developers to write new code only if an automated test has failed, and to eliminate duplication. The goal of TDD is l d l h l f clean code that works” [ Mansel&Husted: JUnit in Action] CISS
TDD D fi ifi TDD Definifion [ [ Agile Alliance] l ll ] “ “Test Driven Development is the craft of producing l h f f d automated tests for production code, and using that process to drive design and programming that process to drive design and programming For every bit of functionality you first develop a For every bit of functionality, you first develop a test that specifies and validates what the code will do. do You then produce exactly as much code as You then produce exactly as much code as necessary to pass the test. Then you refactor (simplify and clarify) both production code and test code” CISS
P Possible test processes ibl t t Test Last (waterfall) Test Last (waterfall) Write Test Specification Code Impl. cases Test Concurrently Write Test (independently) (i d d tl ) cases Specification Code Impl. Test First Write Test Code Impl. Specification cases cases CISS
W h t i TDD? W hat is TDD? TDD is a technique whereby you write your test h h b cases before you write any implementation code code Tests drive or dictate the code that is developed An indication of “intent” An indication of intent Tests provide a specification of “what” a piece of code actually does Thinking about testing is analysing what the system should do! Some might argue that “tests are part of the Some might argue that “tests are part of the docum entation ” Mainly Unit Testing a y U t est g Automated Regression Unit Testing CISS
R Requirem ents i t Domain Experts Standards Standards Informal understanding in developer’s mind Written specs Customers (iinformal, ncomplete, ambiguous) CISS
A t Autom ated Testing t d T ti “Code that isn’t tested doesn’t work” “Code that isn’t regression tested suffers g from code rot (breaks eventually)” “If it is not automated it is not done!” If it is not automated it is not done! “A unit testing framework enables efficient and effective unit & regression efficient and effective unit & regression testing Programmer Friendly P F i dl CISS
R Regression testing i t ti New code and changes to old code can affect the rest of the code base “Affect” sometimes means “break” Regression = Relapsed to a less perfect g p p or developed state. Regression testing: Check that code Regression testing: Check that code has not regressed Regression testing is required for a Regression testing is required for a stable, maintainable code base CISS
R f Refactoring t i Refactoring is a behavior preserving transformation Restructure, simplify, beautify Refactoring is an excellent way to break Refactoring is an excellent way to break code. CISS
Testing using xUnit T ti i U it Refactor code tests [ Pass] tests [ Pass] Refactor code tests [ Fail] All t All tests t Some tests S t t Fix code pass p fail Write Failed test Can’t think of any more tests t t CISS
B Benefits? fit ? Efficiency ff Identify defects earlier Identify cause more easily Identify cause more easily Higher value of test effort Producing a more reliable system Producing a more reliable system Improve quality of testing (maintain automated tests) Minimization of schedule Stable code base Reducing Defect Injection Small “fixes” have are 40 times more error prone than new code = > Fine grained tests + run tests continuously co t uous y CISS
B Benefits? fit ? Better programmer Life Can now work on your code with no fear; No one wants to support a fragile system; “We don’t touch that, it might break.” With complete tests code away: With complete tests, code away: Test fails, you * know* you broke something. Tests pass, you didn’t. Eases changes (XP embrace change): addition of functionality addition of functionality new requirements refactoring refactoring CISS
TDD St TDD Stages In Extreme Programming Explored (The Green Book), Bill Wake describes the test / code cycle: Write a single test Write a single test 1 1. Compile it. It shouldn’t compile because you’ve not 2. written the implementation code Implement just enough code to get the test to compile 3. Run the test and see it fail 4. Implement just enough code to get the test to pass I l t j t h d t t th t t t 5. Run the test and see it pass 6. Refactor for clarity and “once and only once” Refactor for clarity and once and only once 7 7 . Repeat 8. CISS
D Developm ent Cycle l t C l add a test [Pass] run the test th t t [ Pass] Development [Fail] continues continues add functionality [Fail] [Fail] run the test [Development stops] CISS
TDD Exam ple Si Sim ple Light-Controller l Li ht C t ll Light controller toggles light on/ off when wire is touched switch On Off switch CISS
TDD E TDD Exam ple l • Writing test case first voi d t est Swi t ch( ) { i d i h( ) { s=new Li ght Swi t ch( ) ; check( s! =NULL) ; check( O check( O N == s. swi t ch( ) ) ; N == s swi t ch( ) ) ; check( O FF ==s. swi t ch( ) ) ; check( O N == s. swi t ch( ) ) ; } • Run tests: (Fails: compilation errors) ( p ) • LightSwitch doesn’t exist CISS
TDD E TDD Exam ple l • Write a first simple implementation Cl ass Li ght Swi t ch { publ i c enum Li ght St at e { O N, O FF} st at e; publ i c Li ght Swi t ch( ) { st at e=O FF; } Li ght St at e swi t ch( ) { Ret ur n st at e; } } • Run Tests • System Compiles • T Test still fails (passes first check) t till f il ( fi t h k) • Switch not fully implemented CISS
TDD E TDD Exam ple l • Implement switch-method Cl ass Li ght Swi t ch { Cl ass Li ght Swi t ch { Cl ass Li ght Swi t ch { Cl ass Li ght Swi t ch { publ i c enum publ i c enum publ i c enum publ i c enum Li ght St a Li ght St at e { O Li ght St a Li ght St at e { O t e { O t e { O N, O N, O N, O N, O FF} st at e; FF} st at e; FF} st at e; FF} st at e; publ i c Li ght Swi t c publ i c Li ght Swi t ch( ) { st at e=O publ i c Li ght Swi t c publ i c Li ght Swi t ch( ) { st at e=O h( ) { st at e=O h( ) { st at e=O FF; } FF; } FF; } FF; } Li ght St at e swi t ch( ) { Li ght St at e swi t ch( ) { Li ght St at e swi t ch( ) { Li ght St at e swi t ch( ) { i f ( st at e==O i f ( st at e==O i f ( st at e==O i f ( st at e==O FF) st at e=O FF) st at e=O FF) st at e=O FF) st at e=O N; N; N; N; i f ( st at e==O i f ( st at e==O i f ( st at e==O i f ( st at e==O N N) st at e=O N) st at e=O N ) st at e=O ) st at e=O FF; FF; FF; FF; r et ur n st at e r et ur n st at e; r et ur n st at e r et ur n st at e; } } • Run Test • still fails (passes first two checks) • S Switch incorrect it h i t CISS
TDD E TDD Exam ple l • Rewrite switch-method (perhaps refactor) Cl ass Li ght Swi t ch { publ i c enum Li ght St at e { O N, O FF} st at e; publ i c Li ght Swi t ch( ) { st at e=O FF; } publ i c Li ght St at e swi t ch( ) { i f ( st at e==O i f ( st at e==O N) N) st at e=O st at e=O FF; FF; el se el se st at e=O st at e=O N; N; r et ur n st at e; } } • Run Tests: Test Passes Run Tests: Test Passes CISS
TDD E TDD Exam ple l Light controller toggles light on/ off when wire is touched New Requirem ent: When wire is held the controller decrements the light level g switch dim dim dim dim Bright Dim1 Dim2 Off switch CISS
Recommend
More recommend