Extract Interface and Wrap: or How to Mock the Framework

Extract Interface and Wrap: or How to Mock the Framework

Many .NET framework types, particularly from earlier versions of .NET, aren’t implemented in a way that makes the type easy to construct or mock in tests. The same can be said for many third-party libraries that your (legacy) applications may be dependent on upon. To a certain extent this also could apply to your (legacy) code, which in theory could be modified but large changes may be too risky in the time available. For this post I will focus on one particular type that often is the cause of much pain when trying to get code under test, namely System.Data.DataRow.

Let’s start by imagining we have a class called Calculator with the following method that we want to test:

  public int SumColumns(DataRow values)
  {
      var total = 0;
      if (!(values[0] is DBNull)) total += (int)values[0];
      if (!(values[1] is DBNull)) total += (int)values[1];
      return total; 
  }

The method takes a single System.Data.DataRow parameter, that is assumed to contain two columns, and sums the values of those columns. This is obviously a very simple and contrived example that could easily be refactored without much risk, but let’s pretend that it’s something more complex.

The initial approach to testing this might be to try and construct a DataRow instance. So let’s try that. The DataRow type has only one constructor which is protected internal, so we can’t call directly new DataRow(...). However DataRow is not sealed so we can create a derived type and call the base constructor. Unfortunately at this point we hit a road block in the shape of System.Data.DataRowBuilder which the constructor requires. DataRowBuilder is sealed and does not have a public or protected constructed (nor properties nor methods except those inherited from Object) so we can’t create a DataRowBuilder instance. May be we’re not done yet, what about passing null to the DataRow constructor? No such luck, it throws a NullReferenceException. So it seems there is no simple way of creating a DataRow.

So how do we go about getting our method under test? As implied in the title, one possible method is what I’m calling here “Extract Interface and Wrap”. However before I go into details on that, let us first persevere with trying to create a DataRow instance.

Creating a DataRow via DataTable

As you will no doubt have inferred from the above heading there is a way to create a DataRow if we go via System.Data.DataTable. Instances of DataRow can be created via the public NewRow instance method of DataTable, or via the Add method of a DataTable instances Rows collection. The Add method is probably slightly more useful as can combine creating and populating a DataRow into a single call. However a row can’t be added to a table if it doesn’t match the table schema so it is necessary to first add columns to the table. For example to create a DataRow with two columns to be passed to our method, we need to do at least the following:

  var table = new DataTable();
  table.Columns.Add("Column1");
  table.Columns.Add("Column2");
  var row = table.Rows.Add(72, 167);

At four lines of code this isn’t that much, but of course the length will increase with the number of columns to be set up. The constructed DataRow can now be passed to our method and Asserts called on the output. Now that we know we can create an instance of DataRow why do we need to go any further? After all that wasn’t too painful was it? OK it’s a round-about way but it doesn’t require a huge amount of code. Well let’s answer that with a lazy list of pros and cons.

Pros

  • Creating a DataRow instance doesn’t require refactoring the method under test. If you absolutely can’t modify the code under test, not even slightly, then this is the way to go.
  • Avoids the need for any mocking frameworks. We can construct a concrete type that contains exactly what we need, we don’t need any fancy dynamic mock proxy gizmos thank you very much! OK this point is rather weak. There is of course a cost involved in learning a new technology but is it really too high?

Cons

  • As we’ve seen, creating a DataRow via DataTable is somewhat clunky. The method under test wants a DataRow but we first go about setting up a DataTable. It is not immediately obvious why we’re doing this so we’ll probably have to throw in a few comments to explain ourselves, which means the reader needs to do more thinking than they bargained for.
  • This method is only useful for creating stubs not mocks since the concrete DataRow type doesn’t provide any convenient hooks for asserting behaviour. In our simple example that’s not an issue but in more complex cases it could be.
  • Tests using a concrete type, e.g. DataRow in our example, do not cleanly isolate the code under test since there is a dependency on the concrete types and whatever (possibly unknown) dependencies those classes have.

To my mind in most cases the above cons outweigh the pros. Unless the code under test absolutely must not be touched then the “Extract Interface and Wrap” approach described below is generally a better option.

Extract Interface and Wrap

Let’s look again at the method we are trying to test:

  public int SumColumns(DataRow values)
  {
      var total = 0;
      if (!(values[0] is DBNull)) total += (int)values[0];
      if (!(values[1] is DBNull)) total += (int)values[1];
      return total; 
  }

If we study our method we can see that it only uses the indexer of DataRow and then only to read, no other DataRow members are used. This means, in this case, the extracted interface only needs a read-only indexer with index type int. We could call the extracted interface IDataRow but, since it only contains an indexer, better to choose a more appropriate name, something like IReadableIndexed (only better). The interface would then look like this:

  public interface IReadableIndexed
  {
      object this[int index] { get; }
  }

Now we have the interface we can create a new class which implements the extracted interface and delegates to an internal DataRow instance, i.e. it “wraps” DataRow. For want of a better name, let’s call this wrapper class DataRowWrapper, which is defined as follows:

  public class DataRowWrapper : IReadableIndexed
  {
      // Constructor taking as parameter the DataRow to be wrapped
      public DataRowWrapper(DataRow wrappedDataRow)
      {
          WrappedDataRow = wrappedDataRow;
      }

      private DataRow WrappedDataRow { get; set; }

      public object this[int index]
      {
          get
          {
              // Delegate to wrapped object
              return WrappedDataRow[index];
          }
      }
  }

The IReadableIndexed interface and DataRowWraper class now enable us to make a small refactoring of our method to make it a lot easier to test. First lets change the signature of our method from:

  public int SumColumns(DataRow values);

to:

  public int SumColumns(IReadableIndexed values);

Now you might be thinking “Isn’t that a breaking change? Won’t we have to change all the places that call our method? Hardly a small refactoring!”, and you’d be right, if that was the only change, but we’re not done yet. This is where the wrapper comes in. What we now do is add an overload of SumColumns with the original signature which delegates to the version accepting IReadableIndexed:

  public int SumColumns(DataRow values)
  {
      return SumColumns(new WrappedDataRow(values));
  }

As you can see, we create a new instance of WrappedDataRow, which implements IReadableIndexed, and pass that to our method. This limits the scope of the changes to just the class containing our method. Any code dependent on our method can carry on calling the overload taking a DataRow instance and remain completely ignorant of our new interface. The result of this is we now have a method we can easily test using the mocking framework of our choice, without having a dependency on a difficult to construct concrete class. For example using Rhino Mocks[1] we can write the body of one possible test as:

  var values = MockRepository.GenerateStub();
  values.Stub(v => v[0]).Return(72);
  values.Stub(v => v[1]).Return(167);
  var calculator = new Calculator();
  var result = calculator.SumColumns(values);
  Assert.That(result, Is.EqualTo(72 + 167));

This requires slightly less code to set up the stub than that to create a DataRow (the first three lines above set up the stub the rest would be needed even if creating an instance of DataRow) and, in my opinion, is easier to follow. In general I consider this to be the better of the two approaches, but this approach does require modifying the code to be tested so does carry a greater risk.

Pros

  • When using a suitable mocking framework, such as Rhino Mocks, the test code is simpler and easier to follow.
  • The code under test is better isolated. There is no dependency on a concrete type and all its related dependencies; the only dependency is on a single interface.
  • As we are using an interface, we can just as easily create mock objects as we can stubs allowing us to verify behaviour as well as state.

Cons

  • Requires creation of new production code in the shape of the extracted interface and wrapper class.
  • Requires modification of the code to be tested before any tests have been written. The changes are small but there is a small risk that the refactoring to use the interface will introduce a bug that isn’t picked up by the unit tests.

The “Extract Interface and Wrap” technique can be a very useful tool to get framework dependent code under test but is not completely without risk. Nevertheless in most cases the testing benefits outweigh the slight risk due the small refactoring required.

Addendum

The technique I called “Extract Interface and Wrap” is similar to the “Skin and Wrap the API” and “Adapt Parameter” techniques described by Michael Feathers in Working Effectively with Legacy Code[2]. I would have mentioned this in the original post if I’d thought to review Mr Feather’s excellent book first. Needless to say Working Effectively with Legacy Code pre-dates this post by some years.


Links

  1. Rhino Mocks – A dynamic mock object framework for the .Net platform
  2. Working Effectively with Legacy Code, Michael Feathers, Prentice Hall (publisher), ISBN-10: 0131177052, ISBN-13: 978-0131177055 :- Covers many useful techniques for getting seemingly hard to test code under test.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.