Tuesday, September 8, 2009

Trainwreck Removal

If your test has a trainwreck in it, DO NOT start building the object chain in your setup so that the trainwreck will execute in your test. That will take forever, and the payoff is next to zilch. Instead, extract the trainwreck expression to a private virtual method you can override:
    public void Blah() {
doSomething(ClassName.GetInstanceName().GetInstanceVariable().GetAttribute());
}
becomes:
   public void Blah() {
doSomething(GetAttribute());
}

protected virtual string GetAttribute() {
return ClassName.GetInstanceName().GetInstanceVariable().GetAttribute();
}

It allows you to override "GetAttribute" in your tests, with something as simple as :
   protected override string GetAttribute{ return "okay"; }

Astute readers will realize that this is the Law of Demeter at work.

Advanced students may note that the public method is in the wrong class now. It doesn't use any local methods or variables, indicating very low cohesion. Time to push it one class deeper in the chain and then reevaluate it to see if parts of the expression need to be pushed further down.

This trick will take you from having to test "in context" with tons of object-chain construction to a new situation where testing is absurdly simple. Use trainwreck removal for all complex indirect accesses including singletons.

1 comment:

  1. Haskell gets this for "free" by vigorously enforcing the separation of pure calculations, which operate only on their arguments, from impure statements which interact with things you can't see just by reading the code in front of you.

    I say free because I tried to learn Haskell but only got as far as appreciating the benefits of purity. I never reached the point of productively harnessing it's capabilities.

    They do it by not having objects, and instead have something else. It's remotely like objects but not enough to protect you from a hideous learning curve.

    ReplyDelete