This post will not go into how tests are written. There are many excellent guides to test driven development on the net. I might post some links for this later. On to business…
Code won’t compile unless our objects talk to eachother as the compiler expects.
Take the example of the ATM from my last post. The ATM object has two responsibilities: login, getBalance. The compiler can ensure that a user object only invokes getBalance and login. That is called type safety. If we try to invoke some responsibility of the ATM object such as showStatement, which it does not have in the example, the compiler will scream and wail like a spoiled child. You will be forced to remove the offending line of code. What can go wrong now?
The problem here is that the compiler can only ensure the integrity of type specifications. It cannot enforce processes or business logic.
I’ll explain this by turning back to my ATM example. Let’s write code to call getBalance before calling login. (sounds of typing). Since type specifications are not violated, this compiles. But we are in trouble. Without calling login first, we don’t have an authenticated session. Without starting an authenticated session, how will the compiler know that the request is made by a valid user, or even whose account balance to get?
Bug, boom. What’s worse, we will only discover the error at runtime.
The compiler enforced compliance with type specifications successfully. But it was not enough to save the day.
Tests complement type safety. They reinforce the safety net. Unit tests are meant to run before the program is loaded up live. So we can write unit tests to check that methods are invoked in due process. Instead of stumbling upon the error at runtime, we can preempt it by running a simple battery of tests after compiling the code base. We must then see to it that the code passes all our tests.
Let’s return to my ATM example to illustrate these ideas.
If getBalance is called without starting an authenticated session, we expect it to signal to the caller that this is an error. So we could write a unit test that calls getBalance without calling login. This test should expect an exception as a result of the call, indicating that no authenticated session has been started. If the expected exception isn’t caught, the test must fail.
But this test only verfies the correct behaviour of the getBalance method. Ideally, before any call to getBalance, an authenticated session should have previously been started. We can write unit tests for all methods that call getBalance. They could verify that a session has been started before getBalance is called. How exactly this is done goes beyond the scope of this post.
More on “Test driven development is type safety” later.
0 responses so far ↓
There are no comments yet...Kick things off by filling out the form below.