Monday, September 30, 2013

When to Create a SetUp Method

I recall from back when the Earth was cooling and I was spending a of time in Seattle (read: "living there") that there was a lot of advice flying around about the forces surrounding designing individual tests.

A particular point of interest was when to factor stuff out into a setup method.  One camp said "never factor something into a setup method until it's needed by more than one test."  Another camp said "factor stuff out into a setup method as soon as you reasonably can."

At the time, I didn't really care so I just went along with my friends.  Now I think I do care.  I've noticed that factoring certain things out into a set up method improves the readability of a test, even when there is only one.

That, to me, settles the "when" question by obviating it and uncovering a much more interesting question: what should you factor out into a set-up method?

I've noticed that, for me, there are two kinds of set-up needed: context stuff and test-specific stuff.  The context stuff is obvious.  The test-specific stuff is interesting.

For a human, there is no information in a context-setting line of code.  It is still informative to a compiler, which is why you need it, but a person trying to understand an API would easily fill in the blanks if he never saw that line of code.  The only real effect such a line of code has on a human-reader is to make a test less-readable by adding noise.  An example of context-setting set-up is instantiating the class being tested.

By contrast, the test-specific line of code is very interesting to a human.  It explains what is happening or why it is happening.  Examples of test-specific code would be invoking a method on the class under test or asserting on the results of such an invocation.

Let's look at two examples.

Here's a test with all the set-up in the test method to prevent a preemptive refactor:

[Test]
public void UnderOrdinaryCircumstancesPassesThroughToCore()
{
  var core = new Mock<PathFinder>();
  var specialEdge = new Mock<PathFinderEdge>();
  var specialEdgeFinder =
    SpecialFirstEdgePathFinder.GetInstance(core.Object, specialEdge.Object);
  var origin = Design.Element.GetInstance(null, null, null);
  var keyPath = new[] { Any.Symbol, Any.Symbol };
  var elementPath = new[] {
    Design.Element.GetInstance(null, null, null),
    Design.Element.GetInstance(null, null, null), };
  core.Setup(c => c.Navigate(origin, keyPath)).Returns(elementPath);

  var actual = specialEdgeFinder.Navigate(origin, keyPath).ToArray();

  Assert.That(actual, Is.EqualTo(elementPath));
}

Here's a test with all the set-up in the test method to prevent a preemptive refactor:

[Test]
public void UnderOrdinaryCircumstancesPassesThroughToCore()
{
  var keyPath = new[] { Any.Symbol, Any.Symbol };
  var elementPath = new[] {
    Design.Element.GetInstance(null, null, null),
    Design.Element.GetInstance(null, null, null), };
  core.Setup(c => c.Navigate(origin, keyPath)).Returns(elementPath);

  var actual = specialEdgeFinder.Navigate(origin, keyPath).ToArray();

  Assert.That(actual, Is.EqualTo(elementPath));
}

The two tests specify the exact same thing.  The only difference, in my mind, is how they read.  To me, the latter is a lot more clear than the former.

The process that works for me is as follows:
  1. Write the test with no set-up to discover what the test should be
  2. Make the test pass
  3. In the refactoring phase, move all the "clutter" to a context-setting setup method
I'm open to other arguments but this is working for me now.

Sunday, September 29, 2013

I want to put together a little club of Trikke riders

It's getting close to the end of the riding season in Central Oregon.  I still like to ride in the winter time when the roads are clear.  There's got to be at least one more Trikke rider somewhere in the Bend area.  If that's you and you want a riding partner for some chilly afternoon runs of 3-10 miles somewhere in Bend, let me know.