I want to write some invoicing logic, and I start coding it, using TDD.
The following example is silly, but I'm confident it represents well the everyday dilemma I'm facing
function createTestInvoice(client) {
return Invoice.new(
{
client: client, rows: [
{item: 'apple', quantity: 1, unit_price_ 1}
{item: 'banana', quantity: 2, unit_price: 2}
]
}
)
}
al = Client.new({name: 'Al', can_buy_apples: true)
assert(
createTestInvoice(al).total
).to(equal(5))
john = Client.new({name: 'John', can_buy_apples: false)
assert(
createTestInvoice(al).total
).to(equal(4))
When I start with the implementation I realise that just the following
is not enough, since I need some kind of InvoiceRowFactory
that decides how and if to allow the row
to be stored.
At this point the logic I was testing in this unit would be testing some logic that is included in the InvoiceRowFactory
. A test for it would be:
/* remember: John cannot buy apples */
assert(InvoiceRowFactory.call(john, {item: 'apple', quantity: 1, unit_price_ 1}).to(be(null))
How to proceed now? keep the tests in the specs of Invoice
, or move them to a brand new test file of InvoiceRowFactory
? Both cases feel wrong to be, because
- if I keep the tests here, I'll be testing here something that belongs to another unit, that can and should be tested separately
- if I move the tests, I'll be stubbing the dependency. At that point, in the future, I realise this code is horrible OOP, and want to replace
InvoiceRowFactory
withInvoiceRow
. So a refactorer would love not to break anything while he's refactoring, keeping all the tests all green, but how? He can't, because my test ofInvoice
is too coupled with theInvoiceRowFactory
stub
I just cannot reach the point where I can look at some code and make some changes keeping confident I'll not break anything, because I write such small units, that the only way to improve them is change the way they interact.
Thank you