Working Effectively with Legacy Code: Chapter 9 Summary
Back at it again, this week we will cover chapter 9 of the book titled "I can't get this class into a test harness".
Sometimes it's just hard. But if it were easy then everyone would do it!!
Okay, I'm sorry that sounds a bit cheesy.
Anyways this chapter goes through a series of examples that highlight the most common problems with getting a class into a test harness.
These problems include:
- Objects of the class can’t be created easily.
- The test harness won’t easily build with the class in it.
- The constructor we need to use has bad side effects.
- Significant work happens in the constructor, and we need to sense it.
In the book there are 6 examples, he uses. For the sake of saving your precious time, I only summarised one.
Hi, I'm summarizing the book "Working Effectively with Legacy Code". If you are interested in the book, feel free to check it out here.
Irritating Parameter
This example illustrates a problem which seems simple at first but gets very irritating.
In a billing system, we have an untested Java class named CreditValidator
.
public class CreditValidator
{
public CreditValidator(RGHConnection connection,
CreditMaster master,
String validatorID) {
...
}
Certificate validateCustomer(Customer customer)
throws InvalidCredit {
...
}
...
}
This class essentially checks whether a credit card is valid or not. If not then it throws an InvalidCredit
exception.
Our mission is to add a new method called getValidPercent
which will tell us the percentage of successful validateCustomer
calls we've made over the life of the validator.
But first, we have to get this class under tests. The first step is to see whether we can get a test harness.
public void testCreate() {
CreditValidator validator = new CreditValidator();
}
This is a construction test. We don't have any assertions we just try to create the object.
The current test will fail because we didn't add any parameters so let's try to create objects of RGHConnection
and CreditMaster
.
public void testCreate() throws Exception {
RGHConnection connection = new RGHConnection(DEFAULT_PORT, "admin", "rii8ii9s");
CreditMaster master = new CreditMaster("crm2.mas", true);
CreditValidator validator = new CreditValidator(connection, master, "a");
}
Seems simple right?
Well, we have made a grave error.
Our RGHconnection
object connects to an actual server.
This is the irritating parameter.
To fix that, we have to create a fake RGHConnection
object and make CreditValidator
believe that it's talking to a real one.
To do that we have to refactor RGHConnection
to make it use an interface called IRGHConnection
and using this interface we create a fake class called FakeConnection
.
public class FakeConnection implements IRGHConnection
{
public RFDIReport report;
public void connect() {}
public void disconnect() {}
public RFDIReport RFDIReportFor(int id) { return report; }
public ACTIOReport ACTIOReportFor(int customerID) { return null; }
}
Using this class we can write our tests.
void testNoSuccess() throws Exception {
CreditMaster master = new CreditMaster(“crm2.mas”, true);
IRGHConnection connection = new FakeConnection();
CreditValidator validator = new CreditValidator(
connection, master, “a”);
connection.report = new RFDIReport(...);
Certificate result = validator.validateCustomer(new Customer(...));
assertEquals(Certificate.VALID, result.getStatus());
}
Conclusion
This chapter primarily had very useful examples.
Unfortunately, I couldn't showcase them all but if you are interested then make sure to get the book.
Thanks for reading.