JAW Speak

Jonathan Andrew Wolter

Linking to Miško’s, Russ’ and my Testability Guide

with 3 comments

Reading time: 4 – 6 minutes

I had the great pleasure of collaborating with Miško Hevery and Russ Rufer in creating the Guide for Writing Testable Code. Please feel free to check it out, and leave comments here or on his blog.

Here’s a peek at the different flaws to watch out for, and warn your co-workers about. If you see this in code that is getting checked in, bring it to the attention to your team. See Miško’s post for the full list.

Flaw #1: Constructor does Real Work (link)

  • If you have a constructor that is doing “work” you’ve established a contract that everyone who wants to create this object also is forced to wait for that “work” to happen. This becomes a huge problem in small unit tests. Frequently unit tests create many, many instances of the object under test – and any work you do in the constructor slows down tests.
  • The solution? Break up the responsibility into two objects: a builder of factory to do all the heavy lifting to construct the object, and whatever the original object was that had the heavy constructor. When you split the responsibilities up you will have a better object oriented design, and make it easy for more flexible construction. If you’re tempted to create an init() method and put the work in there – avoid this siren song. It’s a smell of mixed responsibilities and a poorly behaving object that isn’t really ready when the constructor completes.
  • Warning signs are:
    • new keyword in a constructor or at field declaration
    • Static method calls in a constructor or at field declaration
    • Anything more than field assignment in constructors
    • Object not fully initialized after the constructor finishes (watch out for initialize methods)
    • Control flow (conditional or looping logic) in a constructor
    • Code does complex object graph construction inside a constructor rather than using a factory or builder
    • Adding or using an initialization block

Flaw #2: Digging into Collaborators (link)

  • Jumping from one object to another to another to get what you want makes for hard to test and hard to refactor code. This is commonly viewed as the Law of Demeter violation, however you can dig into collaborators without breaking the letter of the law. This is hard to work with in tests, because your tests need to do a great deal of setup stuffing objects in objects into other objects, or else you’ll get null pointers.
  • Warning signs are:
    • Objects are passed in but never used directly (only used to get access to other objects)
    • Law of Demeter violation: method call chain walks an object graph with more than one dot (.)
    • Suspicious names: context, environment, principal, container, or manager

Flaw #3: Brittle Global State & Singletons (link)

  • Global state (usually made possible through the static keyword in Java) creates hard to test and modify code. Parallelizing tests is often impossible, and tests that forget to clean up the global state after running interact undesirably with other tests (causing unexpected failures).
  • Warning signs are:
    • Adding or using singletons
    • Adding or using static fields or static methods
    • Adding or using static initialization blocks
    • Adding or using registries
    • Adding or using service locators

Flaw #4: Class Does Too Much (link)

  • Object oriented design allows you to split responsibilities into individually tested objects. Using an object oriented language does not prevent people from writing procedural code. In fact, most times when someone does not want to write tests it is because their code is hard to test.
  • Warning Signs:
    • Summing up what the class does includes the word “and”
    • Class would be challenging for new team members to read and quickly “get it”
    • Class has fields that are only used in some methods
    • Class has static methods that only operate on parameters

There’s typically no magic wand to wave and make hard to test code instantly testable. Engineers need to have an open mind and learn how to write code designed for testability. (In my experience 90% of the time this involves test driven design and test driven development.) These ideas above, and many of Miško’s other posts are a fantastic starting point for adopting that new way of thinking.

Please link it up with your favorite testability mindset readings.

Bookmark and Share

Written by Jonathan

November 29th, 2008 at 5:26 pm

3 Responses to 'Linking to Miško’s, Russ’ and my Testability Guide'

Subscribe to comments with RSS or TrackBack to 'Linking to Miško’s, Russ’ and my Testability Guide'.

  1. You guys need to write a book. Great stuff.

    rishi

    29 Nov 08 at 6:42 pm

  2. Thanks Rishi — I keep telling Misko he’s on to something here.

    What’s hard is people don’t like to actually implement this stuff. It’s really hard, and takes a lot of discipline from the whole team. They will get slower before the big benefits pile up.

    But then when the foundation is set, team velocity can really soar.

    Jonathan

    30 Nov 08 at 12:31 pm

  3. I’d buy that book! :D You’ve got some great ideas and it will help a lot of people writing unit tests. A lot of people think they write unit tests, when in fact they really don’t. They access the database, file system, network etc.

    Adam

    19 Jan 09 at 8:23 am

Leave a Reply