Testing assumptions with preconditions


While driving design with unit tests, I often break behaviors out into separate classes, both to increase cohesion, and as a side effect, increase testability.  Occasionally, I run into situations where I have some sort of environmental variable that never changes.  Or, if it does change, it would take an act of Congress.

When designing these environmental “astronomical constants”, I take the “JFHCI” approach.  These are values that have never changed, and the customer has told us don’t need to change.  One case I ran in to recently is a reward limit.  If you purchase over X dollars, you earn a reward.  The value X does not change, so I made it a constant:

public const decimal GadgetSpendRewardLimit = 200m;

My “testability” hat on says that constants are bad, and that I need to be able to properly set up all environmental variables.  However, in this case, allowing this value to change in ANY way produces a design that does not match reality.  In reality, this reward limit does not need to change.

Instead of going through a bunch of hoops to allow this value to change solely for testing, I’ll leave the value alone.  However, in the off chance that this value DOES change, my tests make the assumption that this value is this constant.

So, I’ve introduced testing assumptions made in my tests with a set of preconditions in the setup portion of the test:

[SetUp]
public void SetUp()
{
    Debug.Assert(Customer.GadgetSpendRewardLimit == 200m, "Assumes threshold is $200");

I use a Debug.Assert mostly just to signify that I don’t need to test this every time, so I don’t really need a regular test assertion.  Instead, this is just a fail-safe, and matches the intent of assumption validation, rather than behavior validation.

With assumption checking through preconditions, I keep the correct design (an immutable constant), while providing explicit callouts of assumptions made about the “correctness” of my tests.  If my assumptions are wrong, I won’t bother trying to continue the test, as the base set of assumptions the test was built around are no longer valid.

The religion of dependency injection