Quality Assurance Tool: Code Contracts

What if there was a quick and easy way to double the power of unit tests, even hands-​​on tests?

Precursor: The Vienna Development Method

Many years ago at university in the Software Engineering class, the professor discussed the Vienna Development Method (VDM). This was a method to formally specify software and prove the integrity of a design.

Among other rules, VDM spec­ified that, per type of entity (i.e., per class) in the design, you can specify an object invariant. This is a set of condi­tions which must be true at any time inside every instance of the class. For example, you may specify that in an Account class, the Balance property must always be at least as high as the MinimumBalance property.

Another rule spec­ified that, per method (or "procedure"), you need to specify precon­di­tions and postconditions:

  • A precon­dition is a condition which must always be true when the method starts executing.
  • A post­con­dition is a condition that must always be true at the end of the method execution.

Typical examples of precon­di­tions are input para­meter vali­da­tions (such as amount > 0, amount <= MaxAmount, etc.), the fact that the object must already be initialized, etc.

Typical post­con­di­tions are: state is updated, the value returned from a function is not null or inside a given range, etc.

VDM, being a formal method after all, used a math­e­matical expression language to specify these condi­tions and invariants. You could then use math­e­matical methods to "prove" that these condi­tions were met, and that therefore the program was correct. Now, it's a far cry to assume that, if pre– and post­con­di­tions and invariants are indeed always met, the program must be correct. Still, I thought VDM was a valuable spec­i­fi­cation and devel­opment tool.

Much to my chagrin, in the following years I discovered that virtually nobody in the industry had ever heard of VDM or was even inter­ested in applying it! (This was one of my first expo­sures to the sad, sad state of profes­sional software devel­opment, but that's another story).

I did manage to sneak in pre– and post­con­di­tions in C and C++ code by using the assert() function, and later in C# using Debug.Assert(). It did the job, but better stuff was to come.

VDM Comes Alive

Fast-​​forward to 2007. Microsoft Research (MSR) creates Spec#, a superset of C# that adds code contracts to the .NET Framework 3.5. The MSR team is not the first to take VDM's prin­ciples and put them in code; the Eiffel language and the Java Modeling Language (JML) already exist.

Now, in 2009/​2010, they are making this cool stuff available to any CLR-​​based language under the name "Code Contracts".

Here's a simple example:

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
///
/// Gets the total value of the order, before rebates
/// and taxes.
///
public decimal TotalValue
{
    get
    {
        Contract.Requires(this.Lines != null);
        Contract.Ensures(Contract.Result() >= 0);
 
        decimal result = Lines
                .Where(x => x != null)
                .Sum(x => x.NumberOfItems * x.PricePerItem);
        Contract.Assume(result >= 0);
 
        return result;
    }
}

Contract.Requires spec­ifies a precondition.

Contract.Ensures spec­ifies a post­con­dition. Notice that the postcondition(s) are placed together with the precon­di­tions, which keeps things quite clear and readable, much more so than JML, in my opinion.

Now, you don't use code contracts just for declaring spec­i­fi­ca­tions. At runtime, and – here's the kicker – even at compile time, the Code Contracts system can use a static checker to verify the validity of the condi­tions and invariants. This is, therefore, not just a good help to translate spec­i­fi­ca­tions to code, but also to prove that these specs are met. Code Contracts are a great way to complement unit tests – in fact, all condi­tions are eval­uated during your unit tests too, rein­forcing their value.

Contract.Assume, as in the example above, spec­ifies an assumption; this is like an assertion, but weaker. At runtime there is no difference between an assumption and an assertion, but at compile-​​time the static checker will try to prove any assertion and generate a warning if it cannot. Since in the case above the static checker cannot prove that the result will be positive, we instruct the checker to assume that it is so. At runtime, the condition will still be checked and a contract exception will be thrown if it is not met.

Here's another simple example, this time of a contract invariant method:

?View Code CSHARP
1
2
3
4
5
6
[ContractInvariantMethod]
void ObjectInvariant()
{
    Contract.Invariant(Lines != null);
    Contract.Invariant(TotalValue >= 0);
}

In the coming days, I will post more examples and tech­niques for making the most of code contracts in .NET.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

1 Comment

  1. Code Contracts By Example Said,

    February 3, 2010 @ 1:14 am

    […] I blogged about Code Con­tracts as a tool to help you spec­ify and ver­ify code behav­ior. Today let's […]