Test After
We will look at a simple example to illustrate the difference between test first and test after approaches. Let's say we we are building a billing system for a clinic. One of the functionalities is to collect payment from a patient for the services tendered. We will use Test After approach. As an exercise, I created a Patient.java and a getPayment() method. It came to me naturally that in order to calculate amount owed by a patient, I would need a list of services that are provided to the patient. So, I added a parameter to my getPayment method. The implementation looks like the following:
public class Patient {
// ...
public double getPayment(List servicesTendered) {
double payment;
if (servicesTendered.size() > 0) {
payment = calculateAmountOwed(servicesTendered);
makePayment(payment);
} else {
payment = 0d;
}
return payment;
}
// ...
}
The test I produced based on the above implementation is as follow:
public void testGetPayment() {
Patient patient = new Patient();
assertEquals(patient.getPayment(new ArrayList()), 0d);
}
We can easily implement similar test to test for non-zero service list. The above test is good enough for our discussion. So far, everything looks good. I am happy with this implementation.
Test-Driven Design (Test First)
In Test After, I implement getPayment method by thinking of what do I need in order to implement the method. In test first, I have to change my mind set. I need to think of how to create some test code to test the getPayment method. In other words, I need to think of how to use my code in the test. Below is the test code I produced by using test first approach:
public void testGetPayment() {
Patient patient = new Patient();
patient.addService(new Service(LAB_WORK));
assertEquals(patient.getPayment(), 15d);
}
The above test method is different from the previous one. The difference is I don't pass in a list anymore. When I write test first, I am thinking from a patient perspective. When a service is tendered, it should be added to the patient. It is just like an on-line shopping cart. A customer can add any items in store to his/her basket. Similarly, a patient should be able to add services tendered to him/her. Below is the new getPayment implementation.
public double getPayment() {
double payment;
if (servicesTendered.size() > 0) {
payment = calculateAmountOwed();
makePayment(payment);
} else {
payment = 0d;
}
return payment;
}
The calculateAmountOwed method does not need a list of services anymore. The service list is available in the Patient class.
Since we design and write test at the same time, no time is wasted. The test we wrote serves two purposes:
- Artifact. The test tells other developers how to use our code.
- Safety net. The test allows other developers to modify our code confidently.
Further readings:
Neal Ford wrote a nice two parts article on Test-Driven Design with more advance examples:
No comments:
Post a Comment