Code Correctness and Unit Testing in .NET Applications

Unit testing is a popular development practice that consists of writing additional programs that automatically invoke functions in the main program under development. The individual unit tests are small pieces of code that can prove the correctness of some aspects (typically, methods) of software units (typically, classes).

Unit testing is important because it is an automatic tool that can catch regressions (that is, unwanted changes in previously working code) introduced during development and refactoring. However, unit testing in itself is not a fundamental technique that can guarantee the quality or correctness of your software. Why is that so?

The Role of Unit Tests

Like many other things in software, unit tests can be badly written. The worst unit test is one that focuses on a scenario that is not relevant for the application. The best unit test is one written to catch corner cases or edge cases (for example, "What happens if a negative value is entered as salary?") Having many unit tests is not necessarily a sign of good code quality; the relevance of unit tests is what really matters. "Code coverage" is the expression used to refer to the percentage of lines of code covered by unit tests. However, there's no proven relationship between this number and correctness of the code.

On the other hand, unit tests are not part of the contract between the development team and customer. Unit tests are a possible (extra) step you take during development to aid with writing code or figuring out design decisions. Unit tests are written by developers for developers, and aid the team to in keeping confident and on track.

Introducing Code Contracts

An alternate API is emerging in the .NET world to complement unit testing  Code Contracts. In the .NET Framework 4, Code Contracts are an API through which you define preconditions, postconditions, and invariants for your classes. For critical methods on critical classes (and ideally, on every class and method), you express conditions that must be preliminarily verified for the method to run correctly (for example, a temperature cannot be less than -273 degrees Celsius) and that are guaranteed to happen when the method terminates. Code Contracts are an API, so they require code to be embedded in existing classes. It is up to developers to decide whether to keep this code in release builds or limit it to debug builds only.

Code contracts don't replace unit tests, but they are a better for ensuring the correctness of a unit of software for three main reasons. First, they are part of the method implementation and contribute to ensuring the function abides by its expected public contract. Second, they force developers to reason in terms of what each method is expected to do and why. The results of this effort provide guidance when it comes to extending behavior or fixing a bug. Finally, and probably most importantly, Code Contracts are a form of metadata. The information they convey can be consumed by other code analysis tools such as the Microsoft's static checker. In particular, the static checker tool you can get from the DevLabs website runs in the background and is triggered by code changes and compile steps. The static checker ensures that preconditions and postconditions match, and invariants (conditions that must hold for a class at all times) are always met.

Static Analysis

Unlike unit tests, Code Contracts enable static analysis, which provides feedback as code is written. By comparison, a complete a battery of unit tests requires several minutes to run. A static analysis tool doesn't give developers certainty, but it does provide useful information about the code under development.

No external tool can validate the relevance of unit tests. The results of tests may be successful or not, but there's no guarantee about their quality. With Code Contracts, everything is based on what the contracts define on a per-method basis. If the contracts are correct, and no warnings are generated from the static analysis step, then your code is likely to be correct.

Note that "correct" doesn't mean "bug-free." Correctness refers to the correct flow of data and behavior. This can be verified with contracts. Implementation details are verified with unit tests. That's why unit tests and Code Contracts go happily hand in hand.

Unit Tests from Contracts

It's worth noting that Microsoft has released a special tool called Pex that relates to Code Contracts and unit testing. Pex is a smart unit test generator that understands contracts in the code and specializes in high code coverage and high relevance. A Visual Studio add-in, Pex uses the same underlying technology of static analysis to "understand" the most relevant tests to be written for code, and it should be considered whenever unit tests or Code Contracts are in use.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!