OrthoCoders

You can code it, I can help!

I Wrote the Test, Now What?

Working with state

In the previous post I showed some examples of writing specifications using immutable classes. For an introduction to specifications please refer to my post about testing.

There’s no denying that immutability can provide lots of benefits in terms of testing, reducing complexity and lowering coupling. Having a language/paradigm that embraces it could be a huge productivity booster.

Unfortunately that’s not always the case or our choice to make ;).

For methods that are immutable specifying the Pre and Post condition is usually enough. However, is quite common in OOP to call methods that not only use the state of the instance but also modify it.

Using interfaces in order to talk about Pre and Post was sufficient because we were describing only the behavior of the method, not implementation. In contrast exploring the state of an instance of a class implies looking at the implementation.

The class invariant

Lets imagine that we want to implement a sorted Collection that ensures every time I iterate through the collection all the elements will be return by the default order. This time the method will modify the state.

1
2
3
4
5
6
7
/// Using default Comparer<T>
public class SortedCollection<T> : ICollection<T>
{
    public void Add(T e) { ... }

    public IEnumerator<T> GetEnumerator() { .... }
}

Lets focus on the Add method. The test looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Test]
public void It_should_add_the_value_to_the_collection_in_order([RandomValue]T e)
{
  // arrange
  var c = GenerateRandomCollectionOf<T>();

  var expected = c.ToArray().Concat(e).Sort();

  // act
  c.Add(e);

  // assert
  Assert.That(c.ToArray(), Is.EquivalentTo(expected));
}

The failing test is the first part of following TDD and we used the Pre and Post to help us to write it without leaving any scenario out.

Now, in order to write the implementation of the method, lets think about how are we going to keep the elements sorted.

We could use an array to store the values and keep it sorted. How can we specify this?

Similar to having a predicate to describe what happens before and after calling a method we are going to use another predicate to describe a condition that a class has to satisfy for every instance.

This condition is called class invariant (invariant in the sense that does not change) and will enforce a restriction over the implementation of a class.

Considering the case above I want to enforce that my array is always sorted.

1
2
3
4
5
/// Invariant: { _sortedElements is always sorted }
public class SortedCollection<T> : ICollection<T>
{
  private T []_sortedElements;
}

The class invariant has to be satisfied (evaluated to true) before and after each method is called. It is ok if the predicate is false inside the method but we need to work to restore it.

When implementing the Add method we have no choice but to add it to the array and sort it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/// Invariant: { _sortedElements is always sorted }
public class SortedCollection<T> : ICollection<T>
{
  public void Add(T e)
  {
    // The invariant is valid here

    this._sortedElements = _sortedElements.Append(e);
    // The invariant may not be valid here it depends on the value

    this._sortedElements = _sortedElements.Sort();
    // The invariant has to be valid here (and it is)
  }
}

Is that the only implementation possible? Why not sort the elements when I need an enumerator? Something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/// Invariant: { _sortedElements is always sorted }
public class SortedCollection<T> : ICollection<T>
{
  public IEnumerator<T> GetEnumerator()
  {
    // The invariant is valid here

    var result = _sortedElements.Sort().GetEnumerator();
    // The invariat is valid here (state wasn't modified)

    return result;
  }

  public void Add(T e)
  {
    // The invariat is valid here

    this._sortedElements = _sortedElements.Append(e);
    // The invariant is not valid here!
  }
}

It is true, that should pass the test too. However, if we change the implementation then the code will break the invariant. The class invariant “guided” me to choose the implementation.

As an exercise, think about what would be the invariant in that case.

Summary

Finding the invariant helps us to discover the implementation and make sure that our methods are not only valid from the interface point of view but also sound in terms of the internal structure.

If finding pre and post is a hard task (the hardest part of TDD) finding the invariant is even harder. I’m not saying this to discourage you (after reading all the post? C'mon!). Quite the opposite.

Sometimes when writing a test (and later the implementation) we are not sure where to start. We may spend quite a bit of time looking at the test code or a class code with the feeling that something’s wrong, and not sure why.

Having the practice of finding Pre, Post and Invariant in your tool belt can help you identify the reason, simplify your task and assist you to find unwanted complexity and code smells right away.

And if it doesn’t work, clearly is time to go home and have a beer. Either way, you win.

Comments