How should we test the following code
void printIt(int a, int b) {
if (a + b >= 0) {
System.out.println("positive");
} else
System.out.println("negative");
}
Short answer: we shouldn’t. It’s doing far too much. We should rewrite it before testing it.
Step 1: Count responsibilities
- Summate two numbers
- Decide if the sum is positive or negative
- Decide what to print if the result is positive or negative
- Print the result using a sideeffect.
Decide how to refactor it
It is policy to Avoid Side Effects. In addition we have an ‘if statement’ and the policy states ‘Avoid if/switch statements except to create objects’. This if statement isn’t actually that bad (it’s not chaining together a load of business logic), but it’s worth experimenting with getting rid of it.
Suppose we refactored this as
interface PrintIt {
void println(String message);
}
enum Sign {
Positive("positive"), Negative("negative");
public final String name;
public static Sign determine(int value) {
return value >= 0 ? Positive : Negative;
}
Sign(String name) {
this.name = name;
}
}
final private PrintIt printer = //injected by dependency injection;
void printIt(int a, int b) {
printer.println(Sign.determine(a + b).name);
}
Each part of the code is now trivial to test. The test for Sign.determine
handle the responsibility of
determining if positive or negative. We can test the names of Positive
and Negative
. The printit method
just needs to assert that it passed the name of Sign.determine
to the printer.
Alternative Refactoring
Another approach is
private final Printwriter printer = // injected by depedency injection
final static String positive = "positive";
final static String negative = "negative";
void printIt(int a, int b) {
if (a + b >= 0) {
printer.println(positive);
} else
printer.println(negative);
}
This is a little better because we are avoiding singletons. It’s less good because the idea of ‘the sign’ of the sum of the two numbers hasn’t been extracted. If this is a common business thing (and it often is) it would be better as an enum.