Extreme Programming Unit Testing Approach

Patterns Note that unit testing in XP is both a testing and design strategy.


There are different approaches in how to test-code-refactor a complex class hierarchy. Some people are in favor of the nested approach, while others are not. Each of them pose advantages and disadvantages. When is each applicable?

For example, let's say you have to code class A, which you THINK is going to need classes B, C, D, and E. Here are some choices:

Note: test X implies testing class X and having it pass 100% Observation: Maybe THINKING you'll need classes B-E is the mistake?

a) Serial approach
     write test E, write E, test E
     write test D, write D, test D
     write test C, write C, test C
     write test B, write B, test B
     write test A, write A, test A
Advantages: ???

Disadvantages: Violates YAGNI How does this violate YAGNI? It violates YAGNI because you THINK you need classes B-E, but you should not implement them until another class actually needs them.

b) Nested approach

     write test A, write A
          write test B, write B
               write test C, write C
                    write test D, write D
                         write test E, write E, test E
                    test D
               test C
          test B
     test A
Advantages: ???

Disadvantages: Time between implementation and testing could be too extensive, violates YAGNI, nesting is hard to manage

c) Nested approach with partial implementation

     write test A, write A (just enough to pass test), test A
          write test B, write B (just enough to pass test), test B
               write test C, write C (just enough to pass test), test C
                    write test D, write D, (just enough to pass test)
                         write test E, write E (fully), test E
                    write D (fully), test D
               write C (fully), test C
          write B (fully), test B
     write A (fully), test A
Advantages: ???

Disadvantages: Violates YAGNI, nesting is hard to manage

d) Partial nesting approach

     write test A, write A
          write test B, write B, test B
          write test C, write C, test C
          write test D, write D, test D
          write test E, write E, test E
     test A
Advantages: ???

Disadvantages: Dependencies between classes are not tested (Remember class B calls class C, where is this tested?), violates YAGNI.

e) Solution proposed by HagbardCeline (http://groups.yahoo.com/group/extremeprogramming/message/23907)

	Write test A.
	Write enough of A to know how I call B.
		Write test B.
		Write enough of B to know how I call C.
			Write test C.
			Write enough of C to know how I call D.
				Write test D.
				Write enough of D to know how I call E.
					Write test E.
					Write E.
					While Test E fails, continue working on E.
				Write the rest of D.
				While test D fails, continue working on D.
			Write the rest of C.
			While test C fails, continue working on C.
		Write the rest of B.
		While test B fails, continue working on B.
	Write the rest of A.
	While test A fails, continue working on A.
Advantages: The A-E are all written test-first and all pass at 100% before I move on.

Disadvantages: Nesting is hard to manage.

If you only THINK you need B, C, D and E then write A with the parts you think you need represented as attributes or methods of A. (I assume that because thinking about A makes you think about B, C, D and E they, or some parts of them, fall "inside" the "A Space" in some way). When A becomes unwieldy or some good reason appears to factor out one of the MAYBE classes, do it and write tests for the new class and change the tests for the refactored A. Until then you don't have the design information to worry about writing them. If you do have it, then you KNOW you will need them all and the problem is the same as anytime you know you need to write more than one related class. (Interesting, what is clearly implied is that the tests themselves are in some way part of the "code" of the application and hold design information about it.) -- KennethTyler?

Kenneth, to summarize, is this what you mean:

f) Solution proposed by IljaPreuss? (http://groups.yahoo.com/group/extremeprogramming/message/15771)

	write test A, write A, test A
	refactor A to A, B, C, D & E
Advantages: ???

Disadvantages: ???


There seem to be two forces at play here:
  1. HaveOnlyOneFailingTestAtaTime?
  2. Design for the immediate task at hand, that is AvoidSpeculativeDesign?. Specifically YAGNI in terms of actually needing classes B, C, D, and E.

The serial approach satisfies 1 but fails at 2. The nested approach fails at both 1 and 2. The partial nested approach is closer to satisfying 1 but still fails and also fails at 2. Hagbard's approach would seem to be a better variant of the nested approach.

What KennethTyler? describes satisfies both forces but is not exactly equivalent to the IljaPreub? approach.

while task A is not completed
    write test for task A
    write enough to pass test
    if classes becomes unwieldly
        refactor
The main point is that the refactoring doesn't all happen at the end and the initial tests are more for the intended task than the implemented classes. I also add a bunch of white box tests at the end to convince myself that the implemented classes work correctly but those aren't TestFirstByIntention? kind of tests. -- JasonYip


I call this one GrowThenSplit?. I describe it a bit at http://www.xprogramming.com/xpmag/tfd2.htm. -- MichaelFeathers


Egroups Threads:
	http://groups.yahoo.com/group/extremeprogramming/message/15342
	http://groups.yahoo.com/group/extremeprogramming/message/15370
	http://groups.yahoo.com/group/extremeprogramming/message/16139
	http://groups.yahoo.com/group/extremeprogramming/message/16164
	http://groups.yahoo.com/group/extremeprogramming/message/16171
	http://groups.yahoo.com/group/extremeprogramming/message/16181


See ExtremeProgrammingImplementationIssues

EditText of this page (last edited April 2, 2014) or FindPage with title or text search