TDD – Invalid
ShoppingCart Quantity (Part 3 – Refactor)
In Part 2, we applied Test-Driven Development (TDD) to include the
quantity as part of the
InvalidQuantity exception’s error message: ‘-2 is not a valid quantity.‘ or ‘-300 is not a valid quantity.‘, and so on.
Again, here is the unit test verifying this behaviour:
So we have tests confirming negative quantities raise
InvalidQuantity exceptions. We also have a unit test to throw a
ZeroQuantity exception when
ShoppingCart.Add() receives a 0
Why do we need a separate ZeroQuantity exception? Isn’t 0 for the
quantity just another invalid value? True.
ZeroQuantity exception arose because the thinking at the time was along the lines of ‘OK, 0 is a non-sense quantity. What shall we call the custom exception for this situation? How about ZeroQuantity exception.‘
We now realise that 0 is not a special case – it is just another invalid
quantity. In light of this insight, let’s refactor our code. Since we are using TDD, we will write a test before we can program up the implementation code. It is the presence of the test that ‘drives’ us to implement the system behaviour.
Well, we don’t have to write an entirely new test; we can extend our parameterised test by the 0 test case:
Notice the test no longer deals with only negative quantities. 0 is neither negative nor positive. We want the test to cover 0 and negative numbers, or non-positive numbers. We rename the test accordingly. It’s essential to remember that the tests always have meaningful and correct names. Why? Tests are requirement definitions. They tell us what the system does. They should not lie and misinform.
Oh, and we should delete the old test for
ZeroQuantity. If we don’t, we’ll have two tests checking for different outcomes for the same input. One of them would always fail.
OK, let’s run all tests. Here is the result:
Fair enough; we have a failure for the 0 quantity case. A
ZeroQuanity exception is thrown instead of an
InvalidQuantity exception. The definition of Add() confirms as much for a 0
Let’s fix this in Add() by removing the condition checking for a 0 quantity:
Hmm, this is a lot simpler. Let’s run our unit tests:
The tests pass. A 0 quantity now raises an
InvalidQuantity exception, the same as a negative value for the quantity parameter.
We should delete the definition for the
ZeroException – it is no longer needed.
What I find fascinating, is how as part of our refactoring we removed the conditional in Add()
if (quantity == 0)
again, even though ultimately we will need a check like that for throwing InvalidQuantity exceptions:
if (quantity <= 0) throw new InvalidQuantity(quantity);
However, we are not at that point yet – or in other words, we don’t have the unit tests demanding the if (quantity <= 0) conditional yet.
I believe we have come to a point where we can start to move beyond The Thorns and go for The Gold.
Until next time.