1 / 10

TDD Basics

TDD Basics. Tom Clune presiding. Principles. Tests should not duplicate implementation Tests should strive to be orthogonal Tests do not uniquely determine implementation Tests should be fine-grained (small increments). Specific tests should be derived from: Basic requirements

isra
Download Presentation

TDD Basics

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. TDD Basics Tom Clune presiding

  2. Principles • Tests should not duplicate implementation • Tests should strive to be orthogonal • Tests do not uniquely determine implementation • Tests should be fine-grained (small increments). • Specific tests should be derived from: • Basic requirements • Simplest cases • Limiting cases • Triangulation • Only implement to just pass the last test. • Always check that tests initially fail.

  3. Tests vs Implementation • Writing tests is a somewhat different art than writing an implementation. • Requires practice and creativity • Tests drive implementation, but … • Tests do not completely constrain implementation • Examples of bad/useless tests: • Using method to be tested to specify the “expected” clause in an assertion:expected = f(3.)call assertEqual(expected, f(3.)) • Reimplementing method to be tested to specify “expected” clause in an assertion • Sometimes a test is based upon an alternate implementation. • E.g. brute force implementation.

  4. Example Geometric Sum a0 = 1. ratio = 0.5 s = 0 n = 2 do i = 0, n - 1 s = s + a0 * ratio ** i end do expectedSum = s call assertEqual(expectedSum, geometricSum(a0, ratio, n)) real function geometricSum(a, ratio, n) geometricSum = sum( (/ (a * ratio ** (i-1),i=1,n) /) ) end function geometricSum real function geometricSum(a, ratio, n) a_1 = a a_n = a * ratio ** (n-1) geometricSum = (a_n - a_1) / (1 - ratio) end function geometricSum

  5. Orthogonality • Developers should strive to create tests which are mutually orthogonal. • Strive for each test to cover just one implementation “feature”. • Tests which are already covered by other tests are wasteful. • Non-orthogonal tests may be limited in their ability to clearly isolate a single defect. • I believe that exceptions to this rule are frequent, but the goal should be born in mind.

  6. Determinism • Many aspects of implementations are not driven directly by requirements. • Tests only verify behavior of implementations. (Tests are functional implementation of requirements.) • Tests aid the development of an implementation by focusing attention on smaller bits of algorithm. There is no magic. • Especially true for performance - consider multiple algorithms for • Sorting (quick, bubble, …) • Random number generation (LCG, …) • Fourier transform (fast vs slow) • Caveat: may need to “invent” tests to cover intermediate steps • One step/sweep of sorting algorithm • Butterfly operation for FFT • Row reduction for matrix solver

  7. Test Granularity • Each test should generally only drive a few lines of implementation. • Developers often overestimate their amount of code which can be written without introducing a defect. • Discipline requires practice. • The first test for a unit often drives creation of a large amount of “boiler-plate” code. This is ok. • New module, derived type, constructor, and at least one method. • We should try to create templates for most of these items. • If implementation bogs down, backup and make test even smaller/simpler.

  8. Minimal Implementation • Avoid the temptation to implement beyond what is required by the test. • Any such extension is not itself being tested, so might have defects. • “You ain’t gonna need it!” - XP mantra • Save time for creating more/better tests. This is where creative energies should mostly be applied for TDD. • Following this minimal approach requires practice and discipline.

  9. Detailed Example • Implement a “stack” (LIFO) of integers. • A stack is a structure which enables addition and retrieval of items where retrieval is always of the last item added. • Methods: • new()/clean() ! Constructor and Destructor • push() ! Add n to stack • pop() ! Return n from stack • numElements() ! Return number of elements currently in stack.

  10. Excercises • Start from scratch and implement a “queue” (FIFO) analogous to the “stack” in the previous examples. • If you are strong with F90, stretch yourself by using pointers to implement a linked list instead of fixed maximum size. The differences are interesting. • Bonus exercise: Starting from scratch use TDD to create a routine which returns the prime factors of a given integer as an array.

More Related