Chapter 9: I Can’t Get This Class into a Test Harness

Here are the four most common problems we encounter:

  1. Objects of the class can’t be created easily.

  2. The test harness won’t easily build with the class in it.

  3. The constructor we need to use has bad side effects.

  4. Significant work happens in the constructor, and we need to sense it.

1. Objects of the class can’t be created easily

Irritating parameter

It often makes sense to begin tests by passing null to constructors. This way we can see exactly which dependencies we really need.

If the class you are wanting to test has parameters that are required for the test to pass, but are inconvenient, or just don’t make sense in a testing context, you can use Extract Interface on those parameters to allow creating a fake object for the test.

Another option if a problematic dependency isn’t hard-coded into its constructor is to use the subclass and override method, however we need to be careful not to alter the behaviour we want to test when we use it.

Null Object Pattern

See also: Special case objects in Clean Code.

The Null Object pattern is a way of avoiding passing null around in a system. For example, if we had a method that returns an employee given some employee ID, what do we return if that ID has no employee?

for (Iterator it = idList.iterator(); it.hasNext(); ) {
       EmployeeID id = (EmployeeID)it.next();
       Employee e = finder.getEmployeeForID(id);
       e.pay();
}

We have a couple of options,

  1. We can throw an exception, so that we don’t have to return anything, but that just means the caller now has to deal with that exception explicitly.
  2. We can return null, but now the caller has to check for null explicitly.

There’s a third alternative. Does the above code actually care whether there is an employee to pay? Does it need to care? What if we had a class called NullEmployee? An instance of NullEmployee is still a structurally valid employee in that it should be able to be used anywhere a normal employee instance would without causing issues. The difference is that a NullEmployee has no name or address, and telling it to pay does nothing.

Given an Employee class that looked like this:

public class Employee
{
    public Guid Id { get; private set; } = Guid.NewGuid(); 
    public string Name { get; private set; }
 
    public Employee(string name)
    {
        this.Name = name;
    }
 
    public Employee(string name, Guid id)
    {
        this.Name = name;
        this.Id = id;
    }
 
    public virtual void Pay(Money amount)
    {
        // some implementation
    }
}

A NullEmployee class might look something like this:

public class NullEmployee : Employee
{
    public NullEmployee()
    {
        base(string.Empty, Guid.Empty);
    }
 
    public override void Pay(Money amount)
    {
        // override and do nothing
    }
}

Bear in mind that if any returned employees are null employees, the count will be wrong, so apply the appropriate filtering.

Null objects are useful when a client doesn’t care whether an operation is successful. In many cases we can finesse our design so that this is the case. See “Define errors out of existence” in A Philosophy of Software Design.

Hidden Dependency

Hidden dependencies are things that a constructor or method use that aren’t part of the interface. A common example would be most uses of the service locator pattern.

One technique for getting around this problem in a constructor is called Parameterise Constructor. Here we externalise a dependency we have in a constructor by passing it in as an argument. Now we can use extract interface on the class to enable us to create a fake for testing.

A common stumbling block for this technique is the assumption that all clients of the class will have to be changed to accomodate the new constructor, which isn’t the case. We can instead handle it like this:

First, extract the body of the constructor to a new method Initialise.

Then we can create a constructor that has the original signature. Tests can call the parameterised constructor, and clients can call this one, Completely unaware that anything has changed.

Construction Blob

If you have a constructor that internally constructs a large number of objects, trying to use the parameterise constructor technique above could end up with a similarly large number of parameters. It can be even worse if a constructor creates objects, and then uses them to create other objects.

In Java and C# we can use Extract and Override Factory Method on code in a constructor, but it’s usually not a good idea. Functions in derived classes often assume that they can use variables from their base class, but until the constructor of the base class is finished, there’s a chance those variables could be uninitialised.

Another option is Supersede Instance Variable.

This involves writing a setter on the class to allow us to swap in another instance after the object is constructed.

Global Dependencies

Consider the following class:

public class Facility
{
    private Permit basePermit;
 
    public Facility(int facilityCode, String owner, PermitNotice notice)
                throws PermitViolation {
 
        Permit associatedPermit =
            PermitRepository.getInstance().findAssociatedPermit(notice);
 
        if (associatedPermit.isValid() && !notice.isValid()) {
            basePermit = associatedPermit;
        }
        else if (!notice.isValid()) {
            Permit permit = new Permit(notice);
            permit.validate();
            basePermit = permit;
        }
        else
            throw new PermitViolation(permit);
    }
    ...
}

If we were trying to create a Facility in a test, we might do something like this

public void testCreate() {
    PermitNotice notice = new PermitNotice(0, "a");
    Facility facility = new Facility(Facility.RESIDENCE, "b", notice);
}

This compiles okay, but when we go to run the test, we see a problem. The constructor uses a class PermitRepository, which needs to be set up a certain way for the test to work.

The line in question is:

Permit associatedPermit =
            PermitRepository.getInstance().findAssociatedPermit(notice);

We could try parameterising the constructor with this dependency, but this isn’t an isolated case, there are numerous similar usages in constructors, regular methods, and static methods. We can easily imagine spending a lot of time dealing with this problem in the codebase.

PermitRepository is an example of the Singleton design pattern.

Nested dependencies

Say we have an object we want to construct, that displays a SchedulingTask:

public class SchedulingTaskPane extends SchedulerPane{
    public SchedulingTaskPane(SchedulingTask task) {
        ...    
    }
}

Constructing this object requires us to pass it a SchedulingTask, which only has one constructor that looks like this:

public class SchedulingTask extends SerialTask
{
    public SchedulingTask(Scheduler scheduler, MeetingResolver resolver)
    {
        ...
    }
}

It would be very frustrating to find that we need yet more objects to construct Schedulers and MeetingResolvers.

In order to progress we need to take a close look at what we want to do. We want to write tests, but what do we really need from those objects being passed in in the constructor? If we don’t need anything from them in the tests, we can Pass Null. If we just need some basic behaviour, we can Extract Interface or Extract Implementer on the most immediate dependency and use the interface to create a fake object.

But what if the class we want to Extract Interface on inherits from some other class, and all it actually does is override some methods from the parent class? Do we need to also Extract Interface on the parent class? In Java (and presumably C#), we don’t. We can create an interface on the child class that includes methods from the parent.

Aliased Parameter

Consider the following class:

public class IndustrialFacility extends Facility
{
    Permit basePermit;
 
    public IndustrialFacility(
			int facilityCode,
			String owner,
			OriginationPermit permit) throws PermitViolation {
 
        Permit associatedPermit =
            PermitRepository.GetInstance()
                                .findAssociatedFromOrigination(permit);
 
        if (associatedPermit.isValid() && !permit.isValid()) {
            basePermit = associatedPermit;
        }
        else if (!permit.isValid()) {
            permit.validate();
            basePermit = permit;
        }
        else
            throw new PermitViolation(permit);
    }
    ...
}

We want to instantiate this class in a test, but we have a couple of problems.

One problem is that the constructor is accessing a singleton again. We can get around that by using the global dependency breaking technique above. Before we can even get to that however, we have another problem. The OriginationPermit in the constructor is hard to make, it has horrible dependencies. First thought might be that we can use Extract Interface on the OriginationPermit class to get past this dependency. The inheritance tree is what makes that not our immediate answer: OriginationPermit extends FacilityPermit, which in turn extends Permit, and the field we assign into is typed as Permit.

The IndustrialFacility constructor takes an OriginationPermit and attempts to get an associated permit; we use a method on PermitRepository that accepts an OriginationPermit and returns a Permit. If an associated permit is found, it’s assigned to the permit field, if not, the OriginationPermit is assigned to the field.

We could try to create an interface for OriginationPermit, but that wouldn’t help: we’d need to assign an IOriginationPermit to a Permit field, and that won’t compile. The most obvious fix would be to create interfaces all the way down the hierarchy (IPermit, IFacilityPermit, IOriginationPermit) and turn the Permit field into an IPermit.

That’s a lot of work, and the code ends up looking a bit clunky. Interfaces are great for breaking dependencies, but if we get to the point where we have a nearly one-to-one relationship between classes and interfaces, the design starts to break down. If we have no other options, this is fine, but if we do we should explore those first.

Extract Interface is just one way of breaking a dependency on a parameter. Sometimes it’s worth taking a closer look at why the dependency is problematic. It may be difficult to create, or have a bad side effect. Other times it might talk to a database or file system, or it might just be a particularly slow running piece of code. Extract Interface does let us get around these problems, but it does so by completely severing the connection to a class. If only certain parts of a class are problematic, we can use another method and remove only the connection to them.

Taking a closer look at the OriginationPermitclass, we can see that when we ask it to validate itself, it actually goes off to a database.

public class OriginationPermit extends FacilityPermit {
    ...
    public void validate() {
        // form connection to database
        ...
        // query for validation information
        ...
        // set the validation flag
        ...
        // close database
        ...
    }
}

We probably don’t want to do this during a test.

Another strategy we can use is Subclass and Override Method. We can make a class called FakeOriginationPermit that provides methods allowing us to easily change the validation flag. Subclasses can then override the validate method and set the flag any way we want while we’re testing the IndustrialFacility class.

Here’s what that might look like in a first test:

public void testHasPermits() {
    class AlwaysValidPermit extends FakeOriginationPermit {
        public void validate() {
            // set the validation flag
            becomeValid();
        }
    };
 
    Facility facility = new IndustrialFacility(Facility.HT_1, "b", new AlwaysValidPermit());
    assertTrue(facility.hasPermits());
}

Creating classes on the fly like this in test code can be very handy for creating special cases easily.

Source

Working Effectively with Legacy Code, Michael Feathers — Chapter 9, I Can’t Get This Class into a Test Harness.