I'll teach you anything you want to know, just don't ask me any questions.

Testable Code (Part 2)

Lets recap a bit from last time, even though you could just go back and re-read it. I’ll sum up. You want to reduce side-effects where possible.

Benefits of Limiting Side-Effects:

out-of-order / parallel test execution

There’s nothing worse than having the order of your tests matter

no tear-down

if you have real work going on in your test teardown you’re doing it wrong.

less likely for other code to depend on those side-effects

This is subtle, but if you leave side effects hanging around, people might take them for granted and assume that they will always be there. This is important because if you later decide to change your code and remove the side-effects, you may break people.

Benefits of relying on abstractions:

Modular code design has many benefits but for testing the most obvious benefit is being able to use a test double in place of the real concrete implementation. This double allows for your tests to cleanly operate on just the class or method being tested, (the term SUT is often used to describe this) Leave yourself Test-Seams, even if you don’t use them right away. You don’t have to go full Dependency Injection with a framework like Ninject or Funq to reap the benefits of DI. Manual dependency injection works quite well in most cases where you only need to inject either a real concrete class or a test-double. The default for the property or constructor being injected can be the normal dependency for your production code, but leave yourself an area to stitch in the dependency later to isolate your class for the test. For example: (this is totally contrived, sorry, I work in finance.)

The default parameterless constructor handles your default dependency registration, but you’ve left yourself open to inject a dependency later for testing when you need it. You can mark this as internal and expose internals only to your UnitTest project using the InternalsVisibleToAttribute for extra assurance that this method will not be called by normal production code. You could also apply the Conditional attribute and #define a UNIT_TEST preprocessor symbol but that’s getting a bit paranoid. This works pretty well for single dependencies in the ideal case, but if you have more than one you might want to switch over to property injection instead for convenience. The hard-line unit tester in me wants to keep things as dogmatically strict as possible, but it’s not always convenient to follow the rules. Provided you aren’t using the other default dependencies in your tests by accident, injecting one or two dependencies into a class which depends on lots of things through properties seems reasonable. You certainly don’t want to run into this:

public class GodObject
{
public GodObject()
: this(new DatabaseLayer(), new ServiceController(), new LoggingModule(), new WidgetFactory, new OkayYouGetWhereIAmGoingWithThis();
}

That thing is far too dependent on other classes to accomplish the desired task, but if this is a brownfield project and you are in the process of backfilling tests this might be a reasonable approach. At the very least the setup constructor will be a constant reminder that you badly need to refactor that thing as soon as possible.

Okay, that’s all the good advice I can muster right now. Keep on testing and check back soon for more smug than you can handle. Tune in next time for “10 reasons you should stop using LINQ. Seriously. Stop it.”