• Test Driven Development

    Jul 20 2008

    I had heard of Test Driven Development (TDD), an agile development technique, and I knew people I knew were using it. I started using it recently after I finally learned the philosophy behind TDD.

    I had always understood it to be just a method of developing where you just make lots of unit tests. I've tried that and felt it was quite a lot of extra work, rather than just testing by hand as you go. I also thought it was mainly geared to Java-type development and not really web development. It turns out that it was boring and not beneficial because I was writing the tests after I wrote the code!

    The secret to TDD is the whole "driven" part. You create the test before you write a single line of code. This makes you figure out what you want to do first, and forces you to structure the code in a way that makes testing easy. Basically, it forces each chunk of functionality to be in its own function, which makes the functionality more reusable.

    Here's the basic process:

    1. Write a test.
    2. Run the test. Since you're writing a test before the functionality exists, it should definitely fail because you should be testing functionality that doesn't exist yet.
    3. Next, create the simplest thing that makes the test pass. You can even cheat here if it's easier. The sooner you see a passing test, the better.
    4. Once all the tests pass, you refactor your code to make it cleaner and more organized.
    5. Commit to version control (optional).
    6. Repeat.

    You should also make sure you add a test whenever a bug creeps up, or whenever you realise there's some rule or assumption that needs to be made. Essentially, you should make a test any time you change the code. Often enough, you'll surprise yourself that things don't work the way you expect.

    It turns out to be a lot of fun, and psychologically rewarding. By that I mean that you have short problems and successes. You see a red bar, solve the problem, and see a green bar a few minutes later. It makes you feel confident that you're building a system that works perfectly as expected.

    The tools are definitely there for you:

    • For PHP and CodeIgniter, I highly recommend SimpleTest and/or SimpleTester for CodeIgniter. SimpleTest comes with lots of different test types, so you can test MVC controllers by loading URLs, clicking links, and making sure everything is there as expected.
    • For JavaScript and Ajax, there is JsUnit.
    • You can also do browser-side testing with Selenium.
    • And of course, Ruby on Rails is well known for its built-in testing features.

    But even once you have the tools, you might look at your code and wonder where to start. I know I did. Without frequent unit testing, it's easy to end up with different functionality combined across multiple functions.

    But you have to start somewhere. For the next piece of functionality you want to add, create a test for it first. This means you'll have to decide where that code will go. But how will you test the output?

    It might occur to you that you could test the code easily if it were put into a single function in a library somewhere. This might involve creating a new class separate from everything you've done prior. You can always reorganize your existing code out of it's scrambled mess and into a set of easily testable, separated libraries and classes. You just need to start somewhere.

    For more information do a Google search - there's tons written about it, and there are certainly libraries available for all the languages and frameworks you use.

  • Comments

    1. Mauvis at 2:17am on July 21, 2008

    Hi Jesse!

    Very interesting write-up. For JS testing, is there any reason you picked jsUnit over qUnit? I only ask because I've been unit testing with qUnit (based on jQuery) and have no experience with jsUnit. I have heard that jsUnit hasn't been updated in a good long while (2 years) and isn't good with ajax, but none of that has been verified on my part.  Additional links on the topic:

    http://www.reddit.com/info/6ix8f/comments/
    http://www.nabble.com/jQuery-test-suite-and-jsUnit-compatibility-td15882865s27240.html

    Best,

    Mauvis

    2. Stephen Ward at 11:44am on July 21, 2008

    Write the test and then write a program to pass the test... it's an interesting methodology, and definitely one I'd never thought of before.  I'll have to give it a try next time I'm doing heavy development.

    Interestingly enough, I had never heard the term "code refactoring" until reading this article, even though I basically blogged about it last week.  Thanks for teaching me a new term. ;)

    3. Jörn Zaefferer at 4:17am on July 22, 2008

    The difficult thing about TDD is to refactor tests. At some point you have to refactor, otherwise you'll end up with more and more tests that contain a lot of duplication and you have no idea where you should add the new tests.

    Refactoring tests is of course much more risky than refactoring normal code, because you don't have tests to test your tests.

    I found the only way out of that dilemma are better test abstractions. Try to refactor your test code while writing it, the earlier the better. The less duplication you produce while writing them, the less you have to fix later, when you may be unable to fix them.

    Test frameworks like Reduction or ScalaCheck, featuring automated* specification-based testing are an interesting development in test abstraction, yet currently the barrier to entry is way too high to be really useful.

    *) automated in the "automate generating input and output data" sense, not in the "automate running tests" sense.

    4. Jolyon at 12:28pm on July 22, 2008

    Excellent post, Jesse.  I feel that TDD can be especially beneficial for new programmers, or old coders picking up a new language.

    Learning a new language can be frustrating at best, and thoroughly discouraging for some.  Quick return on successes helps inexperienced coders feel more confident and learn the language faster, in my opinion.

    To Jörn:  Refactoring your tests for speed and accuracy can seem daunting, but don't give up on TDD.  Always, always, always retain your first tests, and refactor in a new test series.  Never throw out your original test series!  The originals can be a valuable rules reference and at the very least it always feels good to look back and see how your code has improved through generations. 

    If you want to keep your active test library clean and you have proven your new tests are running well, at the very least copy the original/previous test code out to a Wiki or documentation repository for quick reference.

    Cheers,
    Jt

    5. damu at 12:06pm on August 4, 2008

    Hi Jesse!
    I'm using TDD for one of my actual projects and it looks great. TDD make you think better before write the code and the code you get are more beautiful. ;-)
    Cheers
      Damian

    6. Andy B at 7:11am on August 6, 2008

    Problem with JsUnit is that there's no way to test asynchronous operations.. that and it's a port of jUnit. Like Mauvis I'd recommend qUnit, which does have the ability to test asynchronous code (e.g. ajax calls to external services), and has a pretty testrunner. However, you should be aware that just writing tests may not make your program more reliable, especially if those tests don't test every line of production code, so look at something like jsCoverage (http://siliconforks.com/jscoverage/) that can tell you what percentage of your code you 'covered' with your tests.

    Been developing this way, in addition to using mocks, for a few months now (where we have the tests integrated into the build process for the application itself) and the main benefit I've found is the regression testing nature of it.. modify a global component a few weeks after it's been signed off and watch all your tests passed, thus giving you enormous confidence that it won't break the site. :-)

    7. Mat Ryer at 6:19am on April 14, 2009

    I am involved in a few open-source JavaScript projects which aim to assist in object oriented test-driven JavaScript development.

    They are:

    http://objx.googlecode.com/ - objx is a full OO framework that lets you utilise the most popular OO paradigms including classes, interfaces, objects, inheritance, subclasses, abstraction, polymorphism, decoupling and events.

    http://trialjs.googlecode.com/ - Tiny and simple selection of methods to help unit test JavaScript code.  I.e. trial.doesThrow(function(){}) returns true if the code throws an exception, otherwise it returns false.

    http://fakequery.googlecode.com/ - fakeQuery lets you unit test code that relies on jQuery.  I.e. http://code.google.com/p/fakequery/wiki/Example1

    8. Sebastian at 4:26am on April 21, 2011

    Good summary on TDD!

    You forgot the mother of all tests: Perl has a lot of test modules on CPAN and could test most other languages aswell.

    Test modules on CPAN: http://search.cpan.org/search?query=test::&mode=all

    Sample of a TDD job: http://padre-ide.de/blog/?p=54

    Commenting is now closed. Come find me on Twitter.