Refactoring for unit testing

When we make a unit test, we really want to test one method at a time. The idea being that all other methods are tested elsewhere, so the only responsibility of a particular test is to test a single method.

Consider the following piece of code:

public class SoftwareUnderTest
{
  public Result PopulateResult ()
  {
    Dependency1 d1 = new Dependency1();
    Dependency2 d2 = new Dependency2();

    Result result = new Result();
    result.X = d1.ComplexCalculation1();
    result.Y = d2.ComplexCalculation1() + d1.ComplexCalculation1();
    double? z = d2.ComplexCalculation2();
    result.Z = z.HasValue ? z.Value : d2.ComplexCalculation1()*2 
                                    + d1.ComplexCalculation1();
    result.Name = d1.ComplexCalculation1().ToString() + "name";
    return result;
  }
}

public class Result
{
  public double X { get; set; }
  public double Y { get; set; }
  public double Z { get; set; }
  public string Name { get; set; }
}

We want to test the PopulateResult method, but that method has some semi-complex algorithms and calculations, which makes it difficult. Further the result depends on two external dependencies Dependency1 and Dependency2. We don’t know what these dependencies do. One strategy that I have seen used a couple of times, is to simply run the code, verify the results by hand, and let the unit test verify against that. That might work… for a while, because there are a couple of problems with this approach:

  • We can’t test both branches of the result.Zcalculation.
  • The dependencies might change over time or depend on some external value from a database or a web service, so our unit test might break without changes to our code.
  • We just stated above that we should only test one method, so we are not really interested in testing the methods in Dependency1 or Dependency2.

Let us address these issues one at a time:

Note that I am aware that the in the code above, the calculations could be performed only once, and stored in temporary variables. For the purpose of this discussion, we pretend that each field in PopulateResult() is coded exactly as specified by our costumer.  The code is not optimized with temporary variables, because this will make it easier to refactor the code.

First we need to move some of the complexity out of the PopulateResultMethod(). I have decided to create a new class for this. Whether you need a new class or just refactor the code into more methods in the current class will depend on both complexity and personal preferences. Here I choose to use a class for demonstration purposes, because I can let the class implement an interface, which can be mock’ed.

public interface IXyzCalculator { double CalculateX(); double CalculateY(); double? CalculateZ(); string GetName(); } public class XyzCalculator : IXyzCalculator { public double CalculateX() { var d1 = new Dependency1(); return d1.ComplexCalculation1(); } public double CalculateY() { var d1 = new Dependency2(); var d2 = new Dependency2(); return d2.ComplexCalculation1() + d1.ComplexCalculation1(); } public double? CalculateZ() { var d1 = new Dependency1(); var d2 = new Dependency2(); double? z = d2.ComplexCalculation2(); return z.HasValue ? z.Value : d2.ComplexCalculation1()*2
+d1.ComplexCalculation1(); } public string GetName() { return CalculateX().ToString() + “name”; } }

So now we can  rewrite PopulateResultMethod() like this:

public class SoftwareUnderTest
  {
    private IXyzCalculator _xyzImplementation;
    public IXyzCalculator XyzImplementation
    {
      get
      {
        if (_xyzImplementation == null)
          _xyzImplementation = new XyzCalculator();
        return _xyzImplementation;
      }
      set
      {
        if(_xyzImplementation != null) //make sure that we can't change the instance on the fly.
          throw new InvalidOperationException();
        if (value == null)
          throw new ArgumentNullException(); 
        _xyzImplementation = value;
      }
    }

    public Result PopulateResult ()
    {
      Result result = new Result();
      result.X = XyzImplementation.CalculateX();
      result.Y = XyzImplementation.CalculateY();
      result.Z = XyzImplementation.CalculateZ();
      result.Name = XyzImplementation.GetName();
      return result;
    }
  }

The PopulateResult() method is now much simpler, and we have added the possibility to change XyzImplementation to something that we control ourselves. This method to inject another dependency is called property injection. We can now write this simple unittest (I use Moq for mocking – use whatever you like):

[Test]
public void TestPopulateResult()
{
  var xyzMock = new Moq.Mock<IXyzCalculator>();
  xyzMock.Setup(x => x.CalculateX()).Returns(1.0);
  xyzMock.Setup(x => x.CalculateY()).Returns(2.0);
  xyzMock.Setup(x => x.CalculateZ()).Returns(3.0);
  xyzMock.Setup(x => x.GetName()).Returns("Some name");

  var sut = new SoftwareUnderTest();
  sut.XyzImplementation = xyzMock.Object;

  var result = sut.PopulateResult();

  Assert.That(result.X, Is.EqualTo(1.0));
  Assert.That(result.Y, Is.EqualTo(2.0));
  Assert.That(result.Z, Is.EqualTo(3.0));
  Assert.That(result.Name, Is.EqualTo("Some name"));
}

This test is unbelievable simple, but that is a symptom of well-refactored code.

What to when the dependency does not implement an interface

Next we shall have a look at the XyzCalculator. I will concentrate on the Method CalcualteX():

public double CalculateX()
{
  var d1 = new Dependency1();
  return d1.ComplexCalculation1();
}

The problem with this method is Dependency1. Whenever you new up something inside a method, you loose the ability to control it. The general recommendation is, to never, never, never new up dependencies inside methods. First we will assume that there is an interface IDependency1 that Dependency1 implements and we will do a bit more dependency injection:

private IDependency1 _dependcy1Implementation;
public IDependency1 DependcyImplementation
{
  get
  {
    if (_dependcy1Implementation == null)
      _dependcy1Implementation = new Dependency1();
    return _dependcy1Implementation;
  }
  set
  {
    if (_dependcy1Implementation != null) //make sure that we can't change the instance on the fly.
      throw new InvalidOperationException();
    if (value == null)
      throw new ArgumentNullException();
    _dependcy1Implementation = value;
  }
}

public double CalculateX()
{
  return DependcyImplementation.ComplexCalculation1();
}

This is what we want – CalculateX() is now very simple to test and I will not show the code for that. Unfortunately there is no IDependency1 (as indicated by the red color in the code above), so dependency injection will not work here. Remember that I stated above, that in the example Dependency1 is outside our control, and we can’t just make it implement an interface. To make it work we add an adapter class that is so simple, that we don’t need to test it.

public interface IDependency1
{
  double ComplexCalculation1();
}

public class Dependency1Adapter : IDependency1
{
  private Dependency1 dependency1;
  public Dependency1Adapter()
  {
    dependency1 = new Dependency1();
  }

  public double ComplexCalculation1()
  {
    return dependency1.ComplexCalculation1();
  }
}

We define the interface and let the adapter implement it. The adapters method(s) simply call an instance of Dependency1() directly, so by using dependency injection on the adapter we can effectively mock Dependency1:

private IDependency1 _dependcy1Implementation;
public IDependency1 DependcyImplementation
{
  get
  {
    if (_dependcy1Implementation == null)
      _dependcy1Implementation = new Dependency1Adapter();
    return _dependcy1Implementation;
  }
  set
  {
    if (_dependcy1Implementation != null) //make sure that we can't change the instance on the fly.
      throw new InvalidOperationException();
    if (value == null)
      throw new ArgumentNullException();
    _dependcy1Implementation = value;
  }
}

public double CalculateX()
{
  return DependcyImplementation.ComplexCalculation1();
}

The only change from before (with the red codelines) is that we now instantiate a Dependency1Adatapter in our DI code. Making the unit test is left as an exercise for the reader.

How to mock methods inside the same class

The last thing I will look at is how to mock method calls made internally in the class. The method GetName() makes an internal call to CalculateX():

public string GetName()
{
  return CalculateX().ToString() + "name";
}

As I stated in the beginning of this post, a unit test should only test one unit (one method). That means we have to the GetName(), but CalculateX() is somebody else responsibility, and is assumed to be tested elsewhere. So: more dependency injection, but this time the default value is “this” (the current instance).

private IXyzCalculator _internalXyzCalculatorImplementation; public IXyzCalculator InternalXyzCalculatorImplementation { get { return _internalXyzCalculatorImplementation ?? this; } set { _internalXyzCalculatorImplementation = value; } } public string GetName() { return InternalXyzCalculatorImplementation.CalculateX()

.ToString() + “name”; }

If we don’t inject anything GetName() will work as usual. But in our unit test we can now do this:

[Test]
public void GetName()
{
  var xyzMock = new Moq.Mock<IXyzCalculator>();
  xyzMock.Setup(x => x.CalculateX()).Returns(1.0);

  var xyzCalc = new XyzCalculator();
  xyzCalc.InternalXyzCalculatorImplementation = xyzMock.Object;

  var result = xyzCalc.GetName();

  Assert.That(result, Is.EqualTo("1"+"name"));
}

Summary

Always program against interfaces, and make sure your code support dependency injection.

Always make sure your code is refactored to be simple and thus easily testable.

That’s all folks.

WordPress Tags: unit test,dependency injection,Mock,adapter,interfaces,refactor

Advertisements

About Lund

Owner of iCodeIT, a software consulting company. I am primarily working the .NET development and architecture.
This entry was posted in C#, Unit Testing and tagged , , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s