Monday, May 25, 2009

Strict Unit Tests for Public Data Contracts

Suppose we have the following code:

When testing such a code, it is tempting to modify the visibility of RESULT to package protected in order to write tests that share the constant value:

After all, reuse is good, right?

Well, in this case, I think that reusing this constant is not a good idea if your API is a public one (or if this code gets exposed as a service, which is practically the same thing).

In fact, I advocate to write the test like this:

But why the duplication?

The catch with public APIs is that they create long lasting expectations in an uncontrolled number of users and systems. Consequently, stability should be their essential characteristic. Through interfaces, it is easy to provide an illusion of stability: as long as the API is backwards-compatible binary-wise (or operation-wise for services), it can change at will and life is peachy.

So what is so risky with the static field above?

Well, the fact of the matter is that the value returned by the doThing() method is also part of the contract. Indeed, beyond the object-oriented concept of interface, data is also part of the overall contract with a particular class (or service). So data should exhibit the same stability as the interface itself.

When sharing a constant in the unit test, it is possible to modify the data contract without noticing. Suppose I change the value of RESULT from "Joy" to "Happy". The first test will give me a green light, while the second will be red. And it is the latter that I am looking for: I want my unit tests to tell me that I have broken the data contract of my class.

Not its users...

2 comments:

zepag said...

So in fact, your Fixture is also a part of the SUT ;). Therefore the initial assertion is therefore pointless.
Though I don't think that adding a constant in the test (and not in the SUT) is really an issue, but I don't think that's what you implied ;).

David Dossot said...

Correct, it is sharing constants between the SUT and the unit tests that is an issue.