Design-by-Contract (DbC) v Test-Driven Design (TDD)

A software contract in the Eiffel language

Another bit of software engineering knowledge from my archive relates to two well-known formal quality methods used in software development. This is from a presentation made at ETH Zurich in 2010.

The background to this is my use of the Eiffel language for 25 years, in which Design by Contract (DbC) figures strongly. Its creator, Bertrand Meyer (currently provost Chair of Software Engineering at Schaffhausen Institute of Technology, Switzerland) coined the term, and developed DbC from earlier formulations such as in the Z language, Djikstra etc.

For those not familiar with ‘contracts’, the full form consists of routine pre- and post-conditions and class invariants. An example of a contract is shown below:

fill is
		-- Fill tank with liquid
		-- i.e., no implementation

The contract consists of the require and ensure predicates. The Eiffel website has a full explanation.

DbC was built into Eiffel (since 1988), and has some native supported in some languages like Ada 2012, Clojure, and Kotlin. Many other languages have had additional frameworks or tools created to add contracts, e.g. Java, C#, Groovy and so on.

However, it has to be said that the culture of contract-oriented has not become mainstream, which those of us who use them routinely find strange – they catch so many errors in testing that it is clear they greatly add to the quality of software.

Some experts think that Test-Driven Design (TDD) is a better alternative, since can be used to force developers to prove that each function they write passes an appropriate test, before they write more code. Personally, although I think routine use of unit testing via built-in frameworks is useful, TDD doesn’t replace DbC, and indeed, it can lead some developers to think their software, if passing all its tests, is ‘done’.

Understanding the difference between DbC and TDD is instructive to understanding why TDD, although very useful, doesn’t tell you if your software is correct.

Here’s the basic difference:

  • A DbC contract is a mathematical specification of the valid domain (input state space) and/or result (output state space) of a routine within a class;
  • TDD is development using ‘tests’ that constitute specific points in a routine’s input value space, which test a routine on an instance.

Mathematically, contracts are intensional (i.e. formally stated) definitions of valid state spaces. Tests are a kind of extensional definition in that they form a list of particular input or output values. From tests on their own, it is hard to a) determine what the total valid value space is and b) hard to see the design intent of the routine.

Since you still do testing if you are using DbC, DbC = contracts + tests. If you are using TDD only, you are just using tests – you have no formal statement of the intended valid state space of input values or results. It is therefore a somewhat haphazard exercise to know what tests to write, especially against someone else’s code. How do you know if you have sufficient coverage? Answer: you don’t.

Indeed, the presence of contracts is an important indicator for writing new tests, since the contract is telling you which kinds of values or states will make the software execute correctly or not.

I remain mystified as to why they are not built into more languages.

About wolandscat

I work on semantic architectures for interoperability of information systems. Much of my time is spent studying biomedical knowledge using methods from philosophy, particularly ontology and epistemology.
This entry was posted in Computing. Bookmark the permalink.

5 Responses to Design-by-Contract (DbC) v Test-Driven Design (TDD)

  1. wolandscat says:

    My good friend Andrew Reilly post the following comment, which was mysteriously rejected. So let’s try a bit of post-delivery testing right here:

    [Andrew said:]
    Doesn’t help with specification bugs, unfortunately. I’m willing to bet that utcoffset isn’t an integer in any working system in South Australia…

    The corollary to the old saw that “you can write Fortran in any language” is that you can write bugs in any language. No matter how much correctness proofing or test harnesses you have, you can always implement the wrong algorithm.

  2. Andrew Reilly says:

    Testing, testing. Is this thing on?

    • Andrew Reilly says:

      Yup. Intermittent failure is the hardest thing to debug. Perhaps we’ll never know the cause…

  3. Michael Miller says:


    Would appreciate a Zoom call sometime if possible on semantic interoperability and openEHR.

    Is this possible?


    *Prof. Michael Miller C.Eng, CITP, FBCS, FEDIPLdgPra*


    *The Care Innovation Corporation*

    *UK Mobile:* +447973626260


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s