Ce billet souhaite inaugurer le début d’une série de billets pour mettre en lumière l’ensemble des technologies gravitant autour de la plateforme .Net de Microsoft, l’intérêt que porte Valtech à cette plateforme ainsi que le savoir faire de la communauté .Net au sein de Valtech.
Pour ce premier billet, nous allons nous attarder sur un projet lancé par Microsoft et voué à rejoindre la version 4 du Framework .Net. Cet outil est actuellement déjà disponible, téléchargeable et utilisable pour peu que l’on dispose de la version 2008 de Visual Studio. Ce projet nommé « Code Contracts » consiste, comme son nom l’indique plutôt bien, à la mise en œuvre pour la plateforme .net (et donc pour l’ensemble des langages de la plateforme) du concept de programmation par contrat.
Le concept est relativement simple et « Code Contract » permet de définir au niveau d’une méthode des pré-conditions (instruction Contract.Requires), des post-conditions (instruction Contract.Ensures) et des objets invariants (instruction Contract.Invariant) c’est-à-dire qu’un objet doit remplir une condition pendant tout le temps d’un traitement (de façon à ce que des variables ne prennent pas des valeurs inattendues). Lorsqu’un des contrats n’est pas respecté, une exception est levée du type ContractException indiquant la condition non respectée.
Une telle approche doit permettre d’établir un contrat fort avec une méthode. Il n’est alors possible de l’appeler qu’avec des données valides c’est-à-dire vérifiant les pré-conditions sous peine de lever une exception. Les erreurs de traitements ou les bugs sont plus rapidement détectés grâce aux différents types de contrat disponibles.
Un autre avantage de ce framework est de pouvoir vérifier certains contrats de façon statique à la compilation et de pouvoir ainsi signaler très tôt des conditions non vérifiées au développeur et ceci à travers des warnings.
Parmi les autres objectifs fixés du projet, on notera également la possibilité d’utiliser ces contrats pour générer automatiquement des tests unitaires plus pertinents en évitant les valeurs ne vérifiant pas les pré-conditions ou en utilisant les pré-conditions pour générer des tests avec des valeurs limites.
On peut noter également que cette démarche simplifie l’écriture de tests unitaires car certains contrôles sont maintenant faits par contrat à l’intérieur de la méthode. Les tests unitaires se bornant alors à appeler la méthode avec plusieurs jeux de données et à vérifier que la méthode ne lève pas d’exception de type ContractException. La programmation par contrat n’ôte pas l’absolue nécessité d’écrire des tests unitaires mais permet d’exprimer dans le code des conditions qui auparavant ne pouvaient être que « vérifiées » par l’utilisation de tests unitaires.
« Code Contracts » devrait également pouvoir à terme servir à générer de la documentation plus pertinente en affichant les pré-conditions et les post-conditions dans la documentation des méthodes.
Quelques informations sur l’installation et la configuration.
L’installation du package téléchargé (cf en bas de cet article) intègre directement les fonctionnalités dans Visual Studio.
L’activation des fonctionnalités se fait dans les propriétés du projet, où un onglet a été ajouté (cf image ci-dessous). On peut alors activer les contrôles à la compilation et/ou ceux à l’exécution.

Pour pouvoir utiliser l’API fournie, il convient d’ajouter une référence dans le projet à l’assembly « Microsoft.Contract ».
Voici donc des exemples concrets de code source.
Toutes les méthodes pour définir des contrats sont des méthodes statiques définies dans la classe Contract présente dans le namespace System.Diagnostics .Contracts.
- Définition de pré-conditions :
Contract.Requires( x ! = null );
Contract.Requires( x > y );
- Définition de post-conditions :
normale :
Contract.Ensures( this .F > 0 );
sur une levée d’exception (avec T le type de l’exception) :
Contract.EnsuresOnThrow<T>( this.F > 0 );
sur la valeur de retour (avec T qui est le type de retour de la fonction) :
Contract.Ensures(0 < Contract.Result<T>());
- Définition d’un objet invariant (contrat vérifié tout au long du traitement) :
Contract. Invariant ( this .y >= 0 );
Contract. Invariant ( this .x > this.y );
- Définition d’une assertion (le contrat doit être vérifié à un endroit précis du traitement) :
Contract.Assert( this .x == 3, "la valeur devrait être 3" );
Voici donc un exemple un peu plus complet :
public class CodeContract
{
public static void Main(string[] arg)
{
CodeContract cc = new CodeContract();
cc.Test1();
cc.Test2();
}
public void Test1()
{
DivideUnderZero(5, 3);
}
public void Test2()
{
DivideUnderZero(5, 0);
//Warning à la compilation (problème détecté de façon statique)
//contracts: requires is false: denominateur doit être different de 0
}
public float DivideUnderZero(int num, int den)
{
Contract.Requires(den != 0, "denominateur doit être different de 0");
Contract.Requires(num > den);
Contract.Ensures(0 < Contract.Result<System.Single>());
//Warning à la compilation (problème potentiel détecté mais résolu lors de l'execution)
//contracts: ensures unproven
return num / den;
}
}
Pour conclure, je pense que l’introduction de la programmation par contrat introduit dans le framework .Net par une approche très facile à mettre en œuvre aide le développeur à détecter rapidement ces erreurs lors de l’écriture du « bon code ». Ceci convient tout à fait à l’écriture de code métier dans lequel les erreurs peuvent coûter cher et être difficilement détectables. La programmation par contrat est donc un nouvel outil dans l’escarcelle du développeur.
D’aucun pourrait reprocher à cette approche le fait d’avoir un code moins ouvert à l’évolution. Auquel cas je répondrais que toute évolution du code nécessite de toute façon la modification des tests unitaires et donc que la modification des contrats fait aussi dans cette logique d’évolution de façon à écrire et garantir le bon fonctionnement du code écrit.
Sources :
Manuel Utilisateur
Site Web
Téléchargement de Code Contract: