When you code, alternate these activities:
Using this system, all my code is highly decoupled (meaning easy to re-use) because it all already has two users - its clients, and its test rigs. Classes typically resist the transition from one user to two, then the rest are easy. I make reuse easy as a side-effect of coding very fast.
Then, the "remove duplication" phase forces one to examine code for latent abstractions that one could express via virtual methods and other techniques that naturally make code more extendable. This is the "reuse" that the OO hype of the 1980s screamed about.
Uh, item 1 is what your OnsiteCustomer keeps screaming about, and item 2 is just item 1 stated inside-out. They are all easy, especially in this order.
There is a big step between hearing the words of an OnsiteCustomer and understanding the meaning. Translating a business statement into technical language can be a difficult job and one should respect that difficulty. Item 2 recognizes that testing the code often requires exposing some things not necessarily required by the end user. There is a step to go beyond what the user needs to what the test will need.
An example of TDD in action in a simple challenge - to write a programme that produces the correct answers to the game "FizzBuzz": https://www.youtube.com/watch?v=CHTep2zQVAc
I use code to find patterns that I am interested in. I can imagine many possible solutions to programming problems but some are a lot better than others. Rather than use my brain to model the computer in high resolution, I use the computer itself to do the modeling and all I need is to start coding somewhere, make incremental changes and follow what turns out to be interesting. Most of this kind of code is thrown away so why would I want to make it bullet proof up front? If I was creating a UI for a piece of code, I would create many versions until I zeroed in on the one I like. Test first is great if you know exactly the best way to program an explicitly defined program but I rarely get that kind of explicit definition and even if I did, how would I know that technique "best fits" that problem? I would know that if I had coded something very like it before but if I had, then I would just take the code I wrote before and make modifications to it. Creating tests that proves the code works is very hard, except in the simple cases and those probably don't need a test in any case. Tests should be created for code that is a "keeper" which, in my case, is only a small fraction of the code I write.
How do you write a test for something that is constantly changing and you don't know what it's shape or structure will look like?
-- DavidClarkd
Systems created using CodeUnitTestFirst, RelentlessTesting & AcceptanceTests might just be better designed than traditional systems. But they all certainly would support CodeUnitTestFirst while using them better than our current set of systems.
But because so danged many of them were not, we are a little blind to what we could have available on the shelf.
A list of ways that test-first programming can affect design:
- Nope. the problem is: They don't know! [UnskilledAndUnawareOfIt]
I have been working my way through Kent's TDD book for a while now, and applying the principles quite rigorously. I am a real dullard sometimes, because it takes me a horribly long time to understand even simple stuff. I had probably been applying TDD for more than a week before I realized why it works so well (at least for me). There are three parts to this:
Test Driven Development (TDD) by KentBeck
ISBN 0321146530 A Book,
Mailing list: http://groups.yahoo.com/group/testdrivendevelopment.
Test Driven Development (TDD) by DavidAstels?
ISBN 0131016490 another book
JohnRusk worries that one danger of TestDrivenDevelopment is that developers may not take that step that you take. I.e. developers may stay with overly concrete code that satisfies the tests but not the "real" requirements.
To look at it another way, I have always felt that it was dangerous to approach design with (only) particular test cases in mind, since its usually necessary to think about boundary cases, and other unusual cases.
How does XP address that danger? By encouraging developers to write sufficiently comprehensive tests? Or by relying on developers to take that step which you mention, which is saying, "OK, this actually passes my tests, but its not really adequate for the real world because....".
XP addresses that danger with PairProgramming. When obvious boundary cases are overlooked by the programmer driving the keyboard, the programmer acting as navigator points out the oversight. This is an excellent example of a case where a single practice is, by itself, insufficient to reasonably guarantee success but, in combination with a complementary practice, provides excellent results.
TestFirst is a cool way to program source code. XP extends TestFirst to all scales of the project. One tests the entire project by frequently releasing it and collecting feedback.
Q: What "real" requirements can you not test?
This is a good thing; it makes you stop, revert your change, and try again.
Note: here is the link to the pdf file on the yahoo groups area:
I found this unexpectedly awkward to locate by searching, so I thought I'd drop the link in here. -- DavidPlumpton
I've sometimes been an advocate of test driven development, but my enthusiasm has dropped after I've noticed that CodeUnitTestFirst goes heavily against prototyping. I prefer a style of coding where the division of responsibility between units and the interfaces live a lot in the beginning of the development cycle, and writing a test for those before the actual code is written will seriously hinder the speed of development and almost certainly end testing the wrong thing.
Agreed. Please see my blog entry about adapting TDD for mere mortals at http://agileskills2.org/blog/2010/02/07/tdd-adapted-for-mere-mortals/ -- KentTong
: Assuming you're not shipping the prototype, there's nothing particularly in conflict. The prototype is in itself a sort of design test. The trouble with prototypes is that they have this habit of becoming the product...
There are other problems, too. Like OO methodology, the difficulties which test driven development helps with are sometimes caused by itself. Every extra line of code adds to the complexity of the program, and tests slow down serious refactoring. This is most apparent in hard-to-test things like GUI's, databases and web applications, which sometimes get restructured to allow for testing and get complicated a lot. -- PanuKalliokoski
CodeUnitTestFirst goes heavily against prototyping? Strange, I haven't found that to be true, myself. Closer to the opposite, in fact - I start with a very thin shell of a ProtoType?, and as I make progress it fills in with real features. I wonder how what you actually do differs from what I actually do.
Strongly agree. A big side benefit of CodeUnitTestFirst that doesn't get enough attention is how it rearranges your thinking. Instead of thinking "oh I'll need these accessors on these classes, etc" you think in terms of use cases. And you end up with *exactly* what you need, nothing more and nothing less.
I find I have a huge increase in speed in all areas of development when I CodeUnitTestFirst. I honestly believe that anyone who doesn't experience this is either busy knocking down StrawMans, isn't doing it right, or hasn't really given it a chance.
TDDing GUIs is quite frustrating. It may be a lot easier if there were a GUI toolkit available that has been TDDed itself, from the ground up. Anyone interested in such a TDDedGuiFramework project?
You mean like RubyOnRails? -- PhlIp
:-) No, I mean a toolkit for standalone clients (or maybe a hybrid one, people have been experimenting with this already). Something like SWT, but a lot more intuitive :-)
Note that some TDDers abuse MockObjects. Dynamic mock systems like http://classmock.sf.net can make this too easy. A TDD design should be sufficiently decoupled that its native object work fine as stubs and test resources. They help to test other objects without runaway dependencies. One should mock the few remaining things which are too hard to adapt to testing, such as random numbers or filesystem errors.
Some of us disagree with that view, see http://www.mockobjects.com/files/mockrolesnotobjects.pdf for an alternative.
I'd like to revisit a comment that JohnRusk made above:
It seems to me that one danger of TestDrivenDevelopment is that developers may _not_ take that step that you take. I.e. developers may stay with overly concrete code that satisfies the tests but not the "real" requirements.
The principles of TDD can be applied quite well to analysis and design, also. There's a tutorial on Test-driven Analysis & Design at http://www.parlezuml.com/tutorials/tdad/index_files/frame.htm which neatly introduces the ideas.
-- DaveChan
What about extended the principles of TDD beyond testing, analysis, and design. How about using the principles also on user documentation? This idea is described in Purpose Driven Development (PDD) at http://jacekratzinger.blogspot.com/2012/01/purpose-driven-development-pdd.html
"Roman Numerals" is often held up as a good sample project to learn TDD. I know TDD but I'm bad at math, so I tried the project, and put its results here:
-- PhlIp
<shameless plug> Up to date info on tools and practices at http://testdriven.com
-- DavidVydra
I found GNU/Unix command line option parsing to be a good TDD exercise as well. My results here:
OrganicTesting of the TgpMethodology is one way to practice TestDrivenDevelopment. Organic Testing is an AutomatedTests methodology that share resemblance to both UnitTest and IntegrationTest. Like UnitTest, they are run by the developers whenever they want (before check-in). Unlike UnitTest, only the framework for the test is provided by the programmers, while the actual data of the test is given by BusinessProfessionals. In Organic testing like IntegrationTests, in each run the whole software (or a whole module) is activated. -- OriInbar
Another reference: article "Improving Application Quality Using Test-Driven Development" from Methods & Tools
http://www.methodsandtools.com/archive/archive.php?id=20
But what about SecureDesign?? SecurityAsAnAfterthought? is a bad idea and it seems that test-driven development (and a number of other agile processes, though perhaps not all) has a bad habit of ignoring security except as test cases, which isn't always the best way to approach the problem.
-- KyleMaxwell
Hmmmm. Seems to me that TDD deals with security (as well as things like performance) just like any other functional requirement. You have a story (or task) explicitly stating what functionality is needed (e.g., user needs 2 passwords to login, which are stored in an LDAP server; or algorithm needs to perform 5000 calculations per second). You then write tests that will verify functionality. And then you write the functionality itself.
And unlike traditional development, you now have regression tests to make sure that this functionality never gets broken. (i.e., if, due to subsequent coding, the security code gets broken, or the algorithm performance drops off, you'll have a broken test to alert you of that.)
One of the reasons that security is hard is that security is not just a piece of functionality. Okay, there are things like passwords which are security features, but the rest of the code also has to not have security holes, which are NegativeRequirements?; ie, code must not do X.
This is obvious in the case of 'must not overflow buffer', which TDD does address, but is less obvious in things like 'component X should not be able to affect component Y'. How do you test that? (I probably read this in 'Security Engineering', by Ross Anderson, which is now free on the web).
-- AlexBurr?
In the case of "Component A must not affect Component B", how would you evaluate this without test-driven development? If you can't formally define this requirement, then TDD is no better or worse than hoping for the best. (One answer in this case may be rule-based formal validation of the system, which is easy enough to plug into a TDD framework.) -- JevonWright?
Some interesting info on test driven development from E. Dijkstra:
IEEE Software will publish a special issue on Test-Driven Development in July 2007. For more information, see IeeeSoftwareSpecialIssueOnTestDrivenDevelopment
Found this useful illustration of TDD in .NET (Flash screen cast) http://www.parlezuml.com/tutorials/tdd.html
I can't help to mention the awesomeness of DocTest in Python. Not only do you get TDD, but you get code documentation for free, as it integrates DocStrings into every Module, Class, and Method. I'd like to see TDD really integrated tightly into programming environments. DocStrings are accessed via a built-in help() function and encourage a friendly development community. DocTest goes further, encouraging smart design of tests within the DocStrings themselves in ways that simultaneously teach the User what your method and class is supposed to do. Ideally, Interpreted environments should integrate a test() built-in. Then, DocTest could be removed and built into the interpreter environment with it`s companion function "help()". This would allow the "add a test, get it to fail, and write code to pass" cycle to attain a most friendly goal of LiterateProgramming. -- MarkJanssen
BDD (Behavior Driven Development) is a form of TDD (Test Driven Development) where the tests are specified through definition of desired Behaviors, as opposed to writing tests in code (the same code language used for the product). The BDD camp says that you use natural language to describe desired behaviour, and employ testing tools which translate the natural language behaviour specification into tests which validate the product code. This approach recognizes and attempts to address a couple of challenges with testing which I elaborate upon below.
See 'Cucumber' (http://cukes.info/) as one example of a BDD test toolkit.
One strategy with BDD is that you employ test (SDT) developers with much different skills than your product (SDE) developers. You can thereby segregate SDT and SDE developers by skills. Another strategy is that your developers use different tools for product development from test development. This suggests that you use people with different skills (less product intensive skills, btw), to write tests (or the same folks using different skills). But when you choose TDD or BDD as a methodology practice, you need to consider (answer) the questions exposed below.
Building test code to automate the testing of your product code produces a regression problem. You want to avoid placing 'faith' in the production code, and ensure that the code has been tested (verified), but now you have moved your 'faith' into the test code.
This regression problem is a challenge with testing, where you must provide tests which cover the requirements and features of your product, so you have moved (regressed) the problem of (potential) defects in the development into a problem with (potential) defects in the test code. You have now written more code (probably in the same language), but possibly replicated or moved the defect into test code. You are still placing faith, but now in your test code, rather than in your production code.
One strategy is to use SDT's to develop tests, and SDE's to develop products. This can help catch misunderstandings in requirements (win), but only increases the amount of code written, and thus the potential number of defects, adding personnel to develop these tests, and thus adding costs. And you now have a recruiting and motivation problem. You must staff SDE's to build products and SDT's to build tests.
However, we can consider that by using different personnel, defects are statistically less likely to align between product code and test code, because we assume that the SDE's and SDT's are independent. We assume a stochastically independent defect generation (SDE's and SDT's are different people). Thus we expect them to generate defects in different places.
But are these activities stochastically independent? We are relying upon this independence. But agile asks that one agile team combine developers writing production code and developers writing test code. So the same (hard) problems are viewed by the same team, and the same conceptual issues are tackled in code by the same pool of developers. Using different developers to write product and test code gains little practical independence, as developers (SDE or SDT) have essentially the same training and experience.
Consider the strategy that you require different training and experience from SDE and SDT. This regains some missing independence. But unless all developers (SDE and SDT) have essentially the same training, capabilities, and skills, they cannot perform interchangeably on an agile team. And developers undertake extensive training. And now you must separate developers by skill and role. Now you face the choice whether to use more skilled developers to write the product, or to write the tests? Using less skilled developers to write the product impairs your product. Using less skilled developers to write your tests means that you impair your tests. This reduces to a Faustian choice, do you effectively subvert your testing and quality process, or do you sacrifice your product development?
Revisit the recruiting and motivation problem. Suppose you decide to staff SDT's to build tests and SDE's to build products. You have introduced stratification and competition into your development team. Are you going to get equally qualified candidates for both SDE and SDT? Even with the different requirements? Assume that most developers want to advance their careers, and gain recognition and rewards, and become the best developers they can become.
Which path will the best and the brightest want to pursue? Consider that Google hires less than 1% of applicants (lots of people want to work there, so they must want to pursue the 'best' career path). Joel Spolsky (co-founder, Fog Creek Software) writes a blog on software development, (http://www.joelonsoftware.com/), says that you should hire people who are "Smart, and Get Things Done".
Can you effectively use the same people writing both product code and test code? And gain the stochastic independence testing needs? Can you use people with different training and skills, and have them independently build tests? And not sacrifice product development on the altar of quality?
The BDD camp says that you use natural language to describe desired behaviour, which would employ developers with much different skills, and thereby segregate developers by skills. This suggests that you use people with different skills (less product intensive skills, btw), to write tests. This has been exposed as a suspect strategy, but assuming you choose TDD or BDD as a methodology practice, anyway. How do you achieve the best results?
TDD in general and BehaviorDrivenDevelopment in particular are firmly grounded in HoareTriple. I find a useful parallel between a written UseCase document and BDD Feature / Story Narrative.
-- MartinSpamer
See TestFirstUserInterfaces CalvinAndHobbesDiscussTdd TestDrivenAnalysisAndDesign TestDrivenDevelopmentaPracticalGuide TestDrivenDevelopmentChallenges TestDrivenDesignPhaseShift, PowerOfTdd, IeeeSoftwareSpecialIssueOnTestDrivenDevelopment, BehaviorDrivenDevelopment, TestFoodPyramid
CategoryTesting CategoryBook CategoryTestDrivenDevelopment CategoryExtremeProgramming