DASIA 2010 will take place from 1st to 4th June 2010 in Budapest (Hungary). See the DASIA page.

TOPCASED 3.3.0 is based on the latest Eclipse 3.5.1 platform (Ganymede code name).  As usual, you can download the expected feature from the GForge server at the following link

Un poste de Maître de Conférences en Conception et Ingénierie  des Systèmes Complexes est ouvert au département Informatique  et Réseaux de Telecom ParisTech (ENST).

Les candidatures se font par dépôt électronique sur le site : http://services.infres.enst.fr/candidatures/

Les dates importantes pour candidater :
• 31 mars 2010 : date limite du dépôt de candidatures
• fin mars jusqu'à fin avril : auditions des candidats  par le département Informatique et Réseaux
• 17 mai : auditions devant la commission de recrutement
• 2eme quinzaine de mai : notification aux candidats
• 1er Septembre 2010 : date prévisible d'embauche

Informations sur l'environnement du poste :

• Lieu de travail : Paris
• Département Informatique et Réseaux http://www.infres.enst.fr/
• Telecom ParisTech : http://www.telecom-paristech.fr
• Rémunération : http://www.institut-telecom.fr/fr_accueil.html - (rubrique recrutement)

Pour plus d'information veuillez consulter le fichier :
http://www.infres.enst.fr/wp/blog/2010/02/02/ouverture-dun-poste-de-maitre-de-conference/

Eh oui, à défaut de prendre des vacances, je donne actuellement une formation UML dans un lieu paradisiaque : Nouméa !

Voilà la vue de ma chambre d'hôtel ...

INFORSID'2010 c'est parti ...  Parmi les ateliers acceptés un petit clin d'oeil à SEC-SY

SEC-SY : Sécurité des Systèmes d’Information et les Environnements Collaboratifs

 

UML&AADL’2010 Workshop held in conjunction with ICECCS 2010 The fifteenth IEEE International Conference on Engineering of Complex Computer Systems is now close, don't hesitate to go to Oxford for this very interesting day !

Vous pouvez vous inscrire dès aujourd'hui aux conférences Neptune et ERTS qui auront lieu à Toulouse en mai 2010 !

Cette année, l'accent sera mis sur MDE et Embedded Systems.

Un programme très alléchant avec en particulier une journée Neptune sur SysML et MDE le 19 mai ...

 

Lien: http://bit.ly/aX5vsU

pour ceux qui veulent mettre en place des tests rapidement et efficacement sur une application Asp.Net MVC... voici une version courte de mon précédent article.

A l'essentiel cette fois ci, ou comment mettre en oeuvre une politique de tests unitaires qui marche, et qui fait des vrais tests!

 

1) choix des fra mework

2) tests des vues

3) tests des contrôleurs

4) isoler (mock) les contrôleurs de leur partie métier (domaine)

5) inversion de contrôle pour fonctionner en test et hors test sans rien toucher

le détail est à lire ici:

http://bit.ly/aX5vsU

 

 

Hi all,

I have just read a post I thought I should share with you. You may have already heard about jquery and the fact that with the version 1.3, there was a vsdoc file that you could download so that you could have intellisense while writing javascript using jquery. Now, a patch is released for Visual Studio which, enables support for vsdoc files. Not only for jQuery, but for any javascript file.

Here is the link to the original post : http://blogs.msdn.com/webdevtools/archive/2008/11/07/hotfix-to-enable-vsdoc-js-intellisense-doc-files-is-now-available.aspx

Here is the link to the jquery web site, where you can download the vsdoc file : jQuery web-site (look for the "Documentation: Visual Studio")

Of course, vsdoc are not supposed to be deployed. They exists only to help developpers.

Le club Système Complexes de la SEE organise une journée de travail sur l'ingénierie des besoins intitulée: "Les bonnes pratiques de l'ingénierie des besoins",  elle aura lieu au LIP6 (Salle 549 au 5eme étage, Ascenseurs Tokyo) à Paris le 16 Mars 2010, vous pouvez déjà réserver cette date sur vos agendas !!

A noter que cette journée est sponsorisée par la société IBM ,  le LIP6 et la SEE

Télécharger ici le Bulletin d'Inscription

 

Les bonnes pratiques de l'Ingénierie des Besoins

09.00-09.30

Enregistrement et petit déjeuner

09.30-09.45

Bienvenue et présentation de la problématique de l'Ingénierie des Besoins par le Club Systèmes Complexes
Agusti Canals - CS Communication&Systèmes

09.45-10.45

Les bonnes pratiques de l'Ingénierie des Besoins avec DOORS
Jeremy Dick - Integrate

10.45-11.45

Les bonnes pratiques de l'Ingénierie des Besoins avec GORE
Axel van Lamsweerde

11.45-13.00

Pause Repas

13.00-13.30

DOORS et l'environnement RMF (ex-TREK) d'IBM
Frédéric Mercier - IBM

13.30-14.00

GORE et l'environnement OBJECTIVER
Robert Darimont - Respect-It

14.00-14.45

Deux success stories avec DOORS et RMF (ex-TREK)

(20 mn)

Retour d'expérience sur l'outil DOORS dans le domaine de la recherche scientifique
Corinne Segalas

(20 mn)

Gestion des exigences avec DOORS RMF (ex-TREK) dans le domaine de la défense aérienne
Marc  Le Goff - Thales Raytheon Systems

14.45-15.30

Deux success stories avec GORE et OBJECTIVER

(20 mn)

Du cahier des charges d’un sous-système au cahier des charges de l’application toute entière : l’expérience SAFEE
Michel Lemoine

(20 mn)

Apport de la méthodologie GORE aux domaines des règlementations aéronautiques
Michel Lemoine

15.30-16.00

Pause Café

16.00-16.30

La démarche pour l'ingénierie des besoins de la DGA
Alain Dohet - DGA

16.30-17.30

Discussion avec les présentateurs sur les limites, avantages et inconvénients de DOORS et GORE
Fabrice Kordon - LIP6

17.30-17.35

Cloture

 

Du nouveau chez les éditeurs d'outil en ce début d'année 2010 :

Artisan Software Tools, Aonix et Extessy fusionnent pour devenir : atego

Un concurrent plus costaud vis à vis d'IBM/ Rational/ Telelogic ??

Lu dans le communiqué de presse :

Artisan® Software Tools and Aonix® have merged to create a new, stronger independent force in the mission- and safety-critical systems and software development tools market. The merged company is named Atego™ and headquartered in San Diego CA, USA and Cheltenham, UK. Artisan Software Tools is the world’s largest independent supplier of industrial-grade, collaborative modeling tools for complex, mission and safety-critical systems and software and Aonix is a leading supplier of critical systems development tools, virtual machines and services for real-time/embedded Java and Ada solutions.

Lien: http://docs.google.com/View?id=dhp3ggmx_168c5md3p52

 

Bien Tester ASP.Net MVC 1.0

Genèse

ASP.Net MVC est né avec plein de bonnes résolutions, et notament celle d' enfin permettre du test unitaire sur les applications Web programmées avec le framework.Net .

Je dis "enfin" car le Test ne passionne pas les foules, et pas vraiment les développeurs, encore moins les responsables ou les clients qui voient en lui une perte de temps ou source de coûts supplémentaires!

Evidemment - et paradoxalement- nos clients (ou parfois chefs de projets) aimeraient bien voir leurs applications garanties exempte de tout défaut, et donc testées, mais bien souvent n'imaginent pas que cela est possible à faire à moindre coût et par un automate.

Comme ils croient surtout que cela coûte trop cher (ou trop de temps) ils font donc passer à la trappe cette étape, qu'ils rejettent d'ailleurs -à tort- en fin de planning alors qu'elle devrait prendre place dès le tout début du projet en se fondant dans les spécifications (pour en diluer le coût).

Pour ce qui est des technologies .Net, on ne peut pas dire que le test ait été placé au coeur de la plateforme. Il a fallu tout de même attendre la version 4 du framework pour réaliser la notion de "code contract", notion omni-présente dans des langages comme Eiffel dont s'inspire pourtant largement C#.

Pour ce qui est de la programmation Web sur la plateforme Microsoft, les WebForms (ASP.Net classique) étant intestables dans leur coeur, il fallait introduire soi-même le pattern MVC, celui par qui le test est possible, ou utiliser un framework additionnel (Monorail par exemple, donc j'avais parlé ici il y a quelques années http://www.castleproject.org/monorail/index.html )

Heureusement, et presque 10 ans après l'apparition d'ASP.Net, Microsoft rend officiel l'utilisation du pattern MVC. Il était temps! Mais que de retard accumulé par rapport aux autres plateformes!

Aidé par un puissant site de présentation et d'aide aux développeurs ( http://www.asp.net/mvc/ ), les développeurs vont enfin pouvoir sortir du modèle "dictatorial" des Webforms et retrouver des façons de programmer le web plus "dans les normes", ou du moins, plus proches des autres frameworks (JSF, RubyOnRails, PHP, etc...)... et pouvoir enfin envisager de tester facilement et sereinement!

Pourtant, trouver des bons exemples de code de tests (TDD) pour ASP.Net MVC, relève du parcours du combattant: code obsolète, différentes releases de ASP.Net MVC, examples incomplets, y compris dans la doc officielle (et quand ca compile, on peut s'estimer heureux), informations contradictoires, besoin d'utiliser à la fois des Mock-ups et de de l'injection de dépendance.... de quoi décourager le plus motivés des adeptes du TDD comme moi.

Quasiment tous les articles qui datent de 2008 sont obsolètes (par exemple http://dotnetslackers.com/articles/aspnet/ASPNETMVCFrameworkPart2.aspx ) mais ils contiennent des idées qu'il faut assimiler.

Indispensable, la classe utilitaire donnée par Scott H. mais qui compile pas :((( http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx

... que d'embuches!

Quand on sait que l'approche TDD (et BDD) [Test Driven Development et Behavior Driven Development ] est la seule qui permette de GARANTIR qu'un logiciel est conforme à ce qu'on attend de lui (via l'écriture de spécification formelles), on a besoin d'y voir clair dans les tests.

Alors voici un article en français qui explique tout, simplement (j'espère), et dont les exemples compilent!

1 - Que faut-il pour tester?

un framework de test est indispensable. Mais lequel choisir? il y en a tellement....

pour comparer d'un point de vue pratique, vous pouvez consulter cette page:

http://xunit.codeplex.com/wikipage?title=Comparisons

mais chacun a ses préférences... difficille de faire un classement objectif et trouver des critères de notations entièrement acceptés par la communauté.

Pour ma part, j'ai choisi xUnit, uniquement pour sa simplicité

http://jamesnewkirk.typepad.com/posts/2007/09/announcing-xuni.html

voici quelques unes de ses caractéristiques:

· Single Object Instance per Test Method.

· No [SetUp] or [TearDown].

· Aspect-Like Functionality.

· Reducing the Number of Custom Attributes.

· [TestFixture] was removed entirely, so tests can be anywhere.

· [Ignore] is expressed using the Skip= parameter on [Test]

· [ExpectedException] was replaced with Assert.Throws.

· [TestFixtureSetup] and [TestFixtureTearDown] are instead expressed as implementations of an interface (ITestFixture).

· Support for IDisposable was added for tests.

2 - Tester, tester.... oui mais tester quoi?


Une application, qu'elle soit Web ou pas, est un ensemble composite.

Il y a multitude de choses qui s'y passe.

Quand on n'utilise pas de pattern et qu'on ne se pré-occupe pas d'architecture logicielle, tout est mêlé dans un code "spaghetti", souvent dans peu de fichiers qui font chacun des milliers de lignes. Dans ce cas, on va avoir beaucoup de mal d'effectuer des tests clairs.

Une Séparation des Responsabilités dans le code (SoC: Separation of Concerns), une architecture N-tiers, une approche Domain Driven, un couplage lâche, une architecture bien pensée, sont évidemment les pré-requis d'un bon projet guidé par les tests (Tests Driven Development).

Le pattern MVC va beaucoup nous aider, puisqu'il sépare le code de la vue, de celui du contrôleur, et du modèle.

Tester la vue en elle même

Pour ce qui est de tester le contenu d'une page HTML, qu'une zone de texte soit bien remplie par la bonne valeur, que la bonne CSS s'applique ou que le nombre d'éléments dans une boite déroulante soit conforme à ce que l'on attend, le Unit Testing n'est pas vraiment l'outil idéal.

Quoiqu'il existe des frameworks qui ont tenté de le faire : http://nunitasp.sourceforge.net/ projet abandonné, ou http://htmlunit.sourceforge.net/ mais pas de portage .Net à ma connaissance.

Il existe malgré tout des outils de tests qui agissent directement sur l'IHM et donc dans notre cas sur le navigateur Web , avec des capacités de comprendre ce qui se passe sur la page HTML (à l’aide de notre ami JQuery) comme le très puissant Selenium IDE ( http://seleniumhq.org/ ) qui va vous générer le code NUnit de test des pages Html à intégrer dans votre solution .Net.  Malheureusement vous serez dépendant d’un serveur Web pour effectuer vos tests, et le principe d’isolation des tests unitaires n’est pas respecté.

En attendant la solution qui comble la brèche…

Tester qu'une vue s'affiche bien

C’est assez trivial mais c'est un début :

[Fact]

public void ReturnsViewResultWithDefaultViewName()

{

// Arrange

var controller = new HomeController();

// Act

var result = controller.Index();

// Assert

var viewResult = Assert.IsType<ViewResult>(result);

Assert.Empty(viewResult.ViewName);

}

Cela permet de vérifier que vous n'avez pas fait de grosses erreurs dans le montage de votre solution Asp.Net MVC. Malheureusement ca ne teste pas des erreurs éventuelles dans le fichier de vue (.aspx)

Notez au passage le tryptique classique d'une méthode de test 1)Arrange 2)Act 3)Assert.

Si votre contrôleur fait passer des bouts de données à la vue par l'intermédiaire du dictionnaire ViewData , il vous suffira de rajouter une ligne:

Assert.Equal("Welcome to ASP.NET MVC!", viewResult.ViewData["Message"]);

Toujours trivial. Et relativement peu utile.

La bonne pratique est d'utiliser une vue fortement typée, ce qui donne quelque chose comme ca dans l'entête de la déclaration de votre vue:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"

Inherits="System.Web.Mvc.ViewPage<ManagePassword.Domain.OperationResult>" %>

ManagePassword.Domain est la librairie de domaine de notre application, et OperationResult est l'objet Modèle (au sens MVC) qui va transiter entre la vue et le contrôleur.

Notre test pourra déjà s'assurer que le contrôleur renvoie bien un objet de ce type là.

// ASSERT

Assert.NotNull(results);

Assert.NotNull(results.ViewData.Model);

var res = Assert.IsAssignableFrom<OperationResult>(results.ViewData.Model);

L'idée d'avoir un modèle déterminé (et donc fortement typé) afin de pouvoir passer de multiples valeurs et tester ce que le contrôleur va retourner à la vue.

Par exemple, on a souvent besoin d'une page qui fait le résumé de l'opération qui vient d'être demandé, et un modèle simple (mais récurrent) pourrait être:

public class OperationResult

{

public bool isOk;

public string errorMessage;

}

Notre test va pouvoir porter maintenant sur les membres du Model, et donc faire plus de vérifications.

// ASSERT

Assert.NotNull(results);

Assert.NotNull( results.ViewData.Model);

var res = Assert.IsAssignableFrom<OperationResult>(results.ViewData.Model);

Assert.Equal(false, res.IsOk);

Tester les redirections

Une redirection peut avoir lieu dans votre contrôleur, la tester permet de savoir par quel point ^de code le contrôleur a terminé son exécution. Pour cela le code de test ressemblera à ceci :

///ACT

var results = controler.ChangePassword(userInfo) as RedirectToRouteResult;

// ASSERT

Assert.True(controler.ViewData.ModelState.IsValid);

// permet de tester que c'est bien un RedirectToRouteResult qui a été retourné (à cause du AS plus haut)

Assert.NotNull(results);

La ligne 1) ne plantera pas au cas où le code du contrôleur ne renvoi pas un objet de redirection ( ). Par contre Assert.NotNull(results); génèrera un échec du test car en cas d’echec du cast par AS, la variable contient le pointeur vers Null.

Pour rappel, une méthode de test ne doit attendre qu’un seul comportement possible.

Si vous voulez tester le cas où le contrôleur ne fait pas d’indirection (et renvoi des valeurs via le modèle), écrivez alors une autre méthode de test pour ce cas là. Attention à ne pas mettre de logique  IF… ELSE…  dans une méthode de test. Car cela est banni.

Dans la vraie vie, le but du programme est de faire en sorte que le Contrôleur appelle un (ou plusieurs) objets du domaine avec un minimum de logique (car la logique doit être dans le domaine). Le contrôleur s’occupe de la logique nécessaire pour préparer l'affichage (et donc le Modèle pour alimenter la vue), et c'est de cela dont il va falloir maintenant s’occuper.

Tester le contrôleur tout seul

Comme je le disais plus haut, la meilleure pratique nous conseille de déporter la logique du domaine (que l'on appelle souvent Métier en France) de l'application.

Hors, dans une démarche de test, la meilleure pratique est de ne tester d’une seule chose à la fois (isolation du test).

Si nous testons le contrôleur, nous devons ne tester que les appels de code dans son corps et non pas tous les objets dont il dépend et/ou auxquels il fait appel.

Il va donc falloir « débrancher » le Contrôleur de tout ce qui pourrait parasiter le test.

Comment faire sans écrire du code compliqué, et surtout sans toucher au code du contrôleur qui doit être transparent au test ? On ne doit pas changer le code de ce qui doit être testé pour le rendre testable ! Sinon le test est biaisé.

Les 2 choses typiques à débrancher sont : le ou les objets de domaine (ou système d’accès aux données), et le contexte sous-jacent au contrôleur (routage, requête http, contexte session, etc.).

Pour ce dernier, ASP.Net MVC est assez bien fait et les dépendances en place n’empêchent pas les tests de fonctionner en isolation, c'est-à-dire sans la présence d’un serveur HTTP.

Ceci dit, si on a besoin de tester le comportement d’un contrôleur en fonction de ce qui peut se passer au niveau Requête HTTP par exemple, on a la possibilité de fournir un faux contexte HTTP.

Vous trouverez de quoi réaliser ceci avec une classe d’aide aux tests, que vous devrez intégrer dans le projet de test : MvcMockHelpers

Vous en trouvez le code ici : http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx

Elle vous propose (entre autres) un FakeHttpContext que vous brancherez à votre contrôleur avec une méthode d’extension, comme celle ci :

controler.SetFakeControllerContext();

Cette classe repose sur un  framework de Mock-up. Le code donné fonctionne avec différentes librairies : RhinoMocks, TypeMock ou Moq.

Personnellement j’ai choisi Moq, car c’est le plus « fluent » au niveau API, sans être abscon, et celui qui a la syntaxe la plus claire pour spécifier le comportement des bouchons, mais nous allons le voir plus loin.

Le seul (petit) problème c’est que cela peut ne pas compiler. Il vous faudra chercher un certain moment sur le net avant de trouver ce « hack » :

http://stackoverflow.com/questions/205644/error-when-using-extension-methods-in-c

et qui vous conseille d’ajouter ces quelques lignes de code au fichier dans lequel vous aurez mis le MvcMockHelpers:

namespace System.Runtime.CompilerServices

{

/// <summary>/// to avoid the following error: Missing compiler required member 'System.Runtime.CompilerServices.ExtensionAttribute..ctor'

/// </summary>

public class ExtensionAttribute : Attribute { }

}

Les méthodes d’extension SetHttpMethodResult et SetupRequestUrl vous seront bien utiles pour tester le comportement de votre contrôleur quand l’invocation se fait par une méthode HTTP GET ou HTTP POST, ou si son code vérifie l’URL demandée.

Bouchons à la rescousse

Mais une bonne partie du comportement d'un contrôleur repose sur l'appel à (et sur les réponses fournies par) un ou plusieurs objets de domaine.

Personnellement je mets toute la logique de mon application dans ces objets et je ne fais pas d'appel aux données directement. Pour ceux qui font le contraire,  la logique de tests est de toute façon la même. Pour que le test puisse tourner indépendamment (sur un serveur de Build ou dans Gallio Icarus par exemple), il ne faut pas de liaison à une base de données ou à tout autre système externe.

C'est aussi pour cela que passer par des objets de domaine, même s'ils ne font que du CRUD, va simplifier le code dans le contrôleur et donc faciliter les tests.

L'avantage majeure résidant dans ces objets de domaine, puisque c'est nous qui les écrivons "à la main", c'est d'avoir une interface que les bouchons vont exploiter.

Je ne vous fais pas l'affront d'expliquer pourquoi une interface est bonne pour votre architecture.

Tout ce qui est à l'extérieur de notre  contrôleur à tester devrait avoir une interface. C'est le cas par exemple d'un Web Service. Quand vous allez vous brancher à une Web Reference, Visual Studio va avant tout construire une Interface (au sens C#) et vous allez pouvoir travailler avec celle-ci.

De toutes façons, il est aisé d’admettre (ou de constater) que tous les frameworks de bouchonnage (mockup) vont exiger une interface afin de pouvoir travailler, donc vous n'avez pas le choix.

Partons du cas où nous avons été de bons élèves et où nous disposons d'une IquelqueChose pour nos objets de domaine (Si ce n'est pas le cas, un petit coup de refactoring et en 3 secondes nous auront ce précieux fichier).

Armé de cette précieuse Interface, donc, vous la passerez en carburant au constructeur du Mock. Avec Moq, cela ressemble à ceci :

//Arrange

// create the mock

var mockRepository = new Mock<IDomainManagingPasswords>();

L’idée est ensuite de faire passer au contrôleur, un objet factice fabriqué par le mockRepository, qui va répondre à l’interface voulue.

Donc vous aurez à modifier le code du contrôleur pour qu'il travaille non plus avec une instance interne du (ou des) objet de domaine, mais avec une référence sur l'Interface, et fourni à l'extérieur du contrôler.  C’est la seule chose que vous devez modifier dans votre contrôleur pour le rendre testable, mais à bien y réfléchir, c’est plus une façon de programmer qu’une contrainte donnée par la démarche de test. Je m’en expliquerai dans un prochain article sur la qualité du code et les enjeux du test dans l’optique de la programmabilité et de la maintenabilité du code.

Cette différente façon de faire consiste à très fortement découpler les objets entre eux. A bien y réfléchir, un objet (ici le contrôleur) a toujours besoin d’un (ou plusieurs) autre objet pour réaliser le comportement attendu. Ne serait-ce que parce que nous avons à notre disposition foultitude d’objets prêt à être réutilisés.

Pour ce faire, nous avions souvent l’habitude d’instancier ces objets tiers, au moment où nous en avions besoin. Parfois, au mieux, nous procédions à leur instanciation/initialisation dans le constructeur de l’objet qui en fait usage.

Ce n’est pas une bonne pratique, car cela ne laisse aucun contrôle sur ces objets (comment ils doivent être initialisés, etc). Il est donc plus profitable (et pas que pour des besoins de tests) de passer des pointeurs sur ces objets au moins au constructeur de celui qui en fait usage, et voir même à chaque méthode dans certains cas.

Pour notre contrôleur cela donne ceci :

private readonly IDomainManagingPasswords _domainObject;

/// <summary>

/// constructeur avec parametre pour accepter le Mocking...

/// </summary>

/// <param name="domainObj">The domain object.</param>

public ManageController(IDomainManagingPasswords domainObj)

{

_domainObject = domainObj;

}

Ensuite à l’intérieur des méthodes du contrôleur, on utilise librement la variable _domainObject comme si de rien n’était.

Cette variable sera occupée par l’objet bouchon lors du test, et cela nous permettra d’ordonner au bouchon d’avoir un comportement A ou B, selon les besoins du test.

Les possibilités donc de « jouer » avec le test sont maintenant très nombreuses.

Par contre, il faut que le contrôleur continue de fonctionner dans son environnement initial, à savoir lorsque le site Web fonctionne dans IIS ou Cassini (ou Apache). Et dans ce cas, le framework Asp.Net MVC s’occupe d’initialiser les contrôleurs, et pour cela il appelle le constructeur sans paramètre de chacun ; ce qui est bien normal, car il n’est pas capable de décider quelle instance d’objet tiers lui passer.

Et évidement, dans ce contexte, on ne travaille plus avec les bouchons mais avec les implémentations « qui marchent » !

Alors comment faire ?

Inversons le contrôle

Il faudrait avoir un mécanisme qui de manière transparente à tout mécanisme (je pense en particulier au mécanisme d’initialisation de Asp.Net MVC, puisse instancier lui-même les objets « qui marchent » et les donner à ceux qui s’en serve.

Dans notre cas, il s’agit de faire passer des objets de domaine correctement instanciés et initialisés, aux constructeurs des contrôleurs lorsque ceux-ci sont mis en route par l’infrastructure de Asp.Net MVC, sur laquelle bien sur nous ne pouvons pas opérer de modification de comportement, puisque le code ne nous appartient pas et qu’il est déjà compilé.

C’est là où l’Inversion Of Control (IoC, tellement plus chic) entre en scène et trouve une de ses nombreuses utilités.

L’idée initiale de l’AOP (qui a inspiré l’Injection de Dépendance) était de permettre au développeur de supprimer la plomberie dans son code, c'est-à-dire sortir toutes les lignes de code qui n’avaient pas vraiment attrait à son algorithme mais qui étaient nécessaires ; sans quoi, justement, les objets dont il dépendait (accès aux données ou à une information tierce) ne pouvaient pas opérer comme il le souhaitait.

Dans le cas du test d’un projet Asp.Net MVC avec de l’injection de dépendance, vous trouverez foison d’exemples et de frameworks.

Quelques points d’entrées :

http://www.mikesdotnetting.com/Article/117/Dependency-Injection-and-Inversion-of-Control-with-ASP.NET-MVC

http://www.rickardnilsson.net/post/2009/12/25/Dependency-injection-in-ASPNET-MVC-with-Unity-IoC-Container.aspx

http://scottfindlater.blogspot.com/2009/11/tdd-mvc-12-inversion-of-control-ioc.html

http://codeclimber.net.nz/archive/2009/02/05/how-to-use-ninject-with-asp.net-mvc.aspx

Mais nous voulons rester pragmatiques, et le problème qui nous intéresse ici est « comment faire en sorte que le contrôleur obtienne un objet de domaine correctement instancié et initialisé quand le projet tourne en mode non-test, c'est-à-dire avec un constructeur sans paramètre ? ».

Mon critère est assez simple : j’ai retenu la solution qui m’oblige à écrire le moins de code possible, qui soit la moins intrusive dans le code existant, et qui m’épargne des lignes de configuration XML qu’on ne sait jamais comment écrire correctement (et auxquelles ont préfère une API fluente, qui permette à l’Intellisense de nous guider intuitivement dans l’usage des objets exposés).

StructureMap est l’un d’entre eux.

Nous avons écrit plus haut un contrôleur MVC doté d’un constructeur avec paramètre qui permet de faire passer une instance d’un objet de domaine.

Hors la fabrique de contrôleurs que Asp.Net MVC utilise en interne ne sait instancier les contrôleurs qu’en utilisant un constructeur sans paramètre. Il faut donc fournir une autre fabrique plus souple.

Heureusement que Scott et son équipe ont tout prévu, et que nous pouvons surcharger la fabrique de contrôleurs par défaut (DefaultControllerFactory) en préparent une autre comme ceci :

using System;

using System.Web.Mvc;

using StructureMap;

namespace yourProject

{

public class DependencyControllerFactory : DefaultControllerFactory

{

protected override IController GetControllerInstance(Type controllerType)

{

return ObjectFactory.GetInstance(controllerType) as Controller;

}

}

}

L’ObjectFactory permettra à StructureMap de résoudre les dépendances et trouver la bonne implémentation concrète de tous ce qui présente une interface remplaçable à la volée par un objet concret.

Ce nouveau Controllerfactory sera enregistré dans la logique Asp.Net MVC en ajoutant une petite ligne dans Global.asax.cs, dans Application_Start() plus précisément :

ControllerBuilder.Current.SetControllerFactory(new DependencyControllerFactory());


Et   juste ensuite (toujours dans Application_Start) nous préciserons à  StructureMap quel mapping opérer entre les interfaces et les implémentations concrètes, comme ici :

ObjectFactory.Initialize(registry => registry

.ForRequestedType<IDomainManagingPasswords>() .TheDefaultIsConcreteType<DomainManagingPasswords>());

Et voila!

C’est assez simple, notez juste que dans cet exemple, mon classe d’implémentation concrète DomainManagingPasswords disposerait d’un constructeur sans paramètre. Pour les cas plus complexes, lire la documentation ici : http://codebetter.com/blogs/jeremy.miller/archive/2008/08/20/smartinstance-in-structuremap-2-5.aspx

Il y a des frameworks IoC qui sont plus explicites encore, et qui vous laissent choisir quelle implémentation viendra s’injecter selon telle ou telle condition.

Cela peut être aussi en intéressant à utiliser si vous voulez par exemple, changer un fournisseur de données par un autre, à la volée dans votre programme.

http://www.iridescence.no/post/Inversion-of-Control-ASPNET-MVC-and-Unit-Testing.aspx

Mais y-a-t-il plus simple ?

Sortir les patterns qui vous font passer pour le roi de la programmation est parfois superflu.

Le crédo est d’être économe, de n’utiliser que ce dont on a besoin. Pourquoi lancer toute la machine d’un IoC, sinon à passer pour un érudit ?

Dans notre cas, nous avions simplement besoin de fournir à la factory par défaut de construction des Contrôleur Asp.Net MVC, un constructeur sans paramètre (tout en gardant celui avec paramètre qui sert aux tests).

Il suffisait d’écrire ce constructeur, et c’est lui qui se chargeait d’instancier l’objet de domaine concret répondant à l’interface IDomainManagingPasswords :

public ManageController()

{

_domainObject = new DomainManagingPasswords();

}

Un bien pour un mal. En faisant cela nous économisons toute la coûteuse introspection qu’opère un Injecteur de Dépendances, mais nous introduisons avant compilation du couplage très fort entre nos classes…

Retour au test, comment pousser le bouchon plus loin ?

Maintenant que nous savons comment faire pour préparer notre objet testé (le contrôleur) pour pouvoir fonctionner de manière identique dans un cas de test ou dans un cas de non-test, voyons comment spécifier le comportement des bouchons pendant le test.

C’est la que notre ami Moq refait surface, et nous permet de piloter le comportement de l’objet « bouchon ».

// create the mock

var mockRepository = new Mock<IDomainManagingPasswords>();

Je veux que lorsque la méthode X mon contrôleur fera appel à la méthode FindUserInAdam de l’objet de domaine qu’elle emploie, et quelque soit la valeur des paramètres, il me retourne une valeur de mon cru, rien de plus simple :

mockRepository.Setup(cr => cr.FindUserInAdam (It.IsAny<string>()))

.Returns(new resultOfSearchingUser

{

errorMessage = "test error",

codeResult = codeResult.NotFound

});

Ce qui se lit (donc se programme) aisément :

Permet de poster les choses.  La lambda expression permet d’exprimer ce qui se passera en cas d’appel à la méthode voulue. Les arguments sont gérés aussi par Moq. It est un objet pratique qui permet de dire « Ceci » est une valeur « peu importe » de type string : It.IsAny<string>().
Ou d’autres formules (une regex par exemple).
Lexpression qui s’en suit dit quoi faire quand la méthode sera réellement invoquée. Ici c’est un retour (Returns) d’une valeur assemblée de toute pièce pour les besoins du test (new resultOfSearchingUser).

N’oubliez pas que les Mocks sont des objets creux, ils répondent à une interface mais ne font rien. Donc à vous de programmer leur comportement.

On pourrait vouloir tester comment le contrôleur réagit si l’objet Bouchon de domaine renvoit une exception. Là aussi, c’est assez simple à exprimer :

mockRepository.Setup(cr => cr.FindUserInAdam (It.IsAny<string>()))

.Throws(new System.OverflowException("test error"));

Pour terminer, on n’oubliera pas de donner en carburant cet objet bouchon au contrôleur avant de lancer (ACT) l’opération à tester:

//bind the mocked object to the controller

var controler = new ManageController(mockRepository.Object);

///ACT

var results = controler.DoFindUser() as ViewResult;


A partir de là, vous avez toutes les billes en main pour tester tout ce que vous pouvez imaginer.
C’est d’ailleurs cette trop grand liberté qui peut être désarmante, et on cherche une méthode pour savoir quoi écrire comme cas de test. La réponse est 2 paragraphes plus loin.

Tester le Modèle

le "Modèle" en tant que structure de données que l'on passe du contrôleur à la vue ne se teste pas en lui-même. Par contre c'est le "fournisseur du modèle" c'est à dire l'objet que vous devez invoquer (et que nous avons substitué par un Mock) qui doit être testé pour lui-même.

A ce moment là c'est un projet de test autour des classes de domaine (classes métier pour ceux qui préfèrent ce terme) aux quelles il faut ajouter une batterie de Tests Unitaires "classiques" pour vérifier leur comportement.

Tout ce que je viens de dire sur les contrôleurs s’applique évidement aux classes de domaines. Elles doivent elles-aussi être fournie avec un jeu de test « en isolation complète ».

3 - Plaidoyer pour une approche Comportementaliste (BDD)

Si vous êtes en mal d’inspiration pour écrire vos tests, voici une idée qui pourra faire son chemin…

Le Behavior Driven Development (ou développement conduit par le comportement et donc les spécifications) devrait être LA façon de programmer universelle.

Affirmer aujourd'hui que la programmation d'un logiciel ne peut se faire qu'en fonction des spécifications passe pour une vérité des plus banales.

Or, jusque là, personne ne s'était occupé de rendre vérifiable, "prouvable" une telle démarche. Le développeur écrivait donc son programme, bon an, mal an. Et vérifiait une fois déployé (en général lors de la préparation de la recette ou de lors de la recette elle même) si le logiciel produit était bien conforme aux spécifications.

Entre écriture des spécifications (en majorité sous forme littéraire) et code (forme "machine", c'est à dire langage de développement) il y a un certain écart, pour ne pas dire un gouffre.

Ce que propose l'approche BDD c'est d'éliminer purement et simplement tout écart.

Et d'écrire les spécifications de manière formelle (donc dans une langue compréhensible par l'ordinateur) et reliée au langage du développement.

Ainsi un automate (un framework de tests unitaires est préposé à cela) peut relier la vérification des spécifications ainsi décrites au code réellement produit.

Le tout, de manière systématique, automatique, constante et répétée (dans le cadre d'une usine logicielle bien construite).

Ce ne sont pas les ressources qui manquent sur le net pour vous expliquer que faire du BDD c'est bon pour vous, essayez par exemple http://behaviour-driven.org/

Ou lisez Dan North, qui est celui qui a posé l'article fondateur : http://dannorth.net/introducing-bdd

Pour ma part, je vous proposerai bientôt un article entièrement consacré au sujet, autour d'une exemple concret bien entendu.

Le BDD est présenté par beaucoup d'éminent spécialiste comme l'aboutissement des méthodes SCRUM et XP

http://www.code-magazine.com/Article.aspx?quickid=0805061

Cette approche est également la plus fidèle à la notion d'Agilité, puisqu'elle permet d'exploiter à 100% les efforts faits en matière de spécification par UserStories et Scenarios.

Mais si elle est légion en Ruby et Python, si on la trouve beaucoup en Java, il faut dire que .Net est à la traine. Et c'est quelque peu frustrant voir même insultant (n'avons nous pas le droit de faire de meilleurs logiciels?)

Cela me rend plutôt inquiet, .Net est-il une plateforme laissée aux seuls Geeks et bricoleur de l'informatique? ou aux sociétés de service pressées de faire du chiffre et ne mettant pas vraiment l'accent sur la qualité logicielle?

Toujours est-il qu'il faut se lever tôt pour trouver un framework prêt à l'emploi, qui fonctionne (sic), et simple à prendre en main (re-sic) pour la plateforme .Net

Beaucoup de projets sont abandonnés en phase initiale (BDD Extensions project on Google Code.)

J'ai essayé de tester tout ce qui était compilable et seul NBehave semble tenir ses promesses; mais comme vous pouvez le voir dans cet article, l'écriture reste peu lisible hélas http://pebblesteps.com/post/Behavior-Driven-Development-with-NBehave.aspx

les BDD extensions de xUnit semblait offrir une forme plus sympathique à lire, mais bon.

Il y avait des initiatives très prometteuses comme  MisBehave, basé sur M et Oslo... mais là encore aucun engouement, ni de la part de la communauté ou des têtes pensantes chez Microsoft (d'ailleurs, que devient M à part un textual DSL pour de la modélisation de données).

Il faudra attendre que la communauté .Net se (re)mobilise et trouve enfin de l'intérêt à faire du BDD pour voir naître un framework nous donnant vraiment envie de faire du comportementalisme et que cette pratique n'apparaisse plus comme une perte de temps, alors que justement c'est le contraire qui devrait en résulter.

4 - D’autres exemples ?

Un projet complet TDD avec MVC plus NHibernate est à découvrir (avec des pages Wiki complètes) sur http://sharparchitecture.net/

Allez voir aussi sur http://scottfindlater.blogspot.com/2009/10/tdd-mvc-adventures.html

Enjoy!


 

Lien: https://twitter.com/guillaume_agile

finalement, Tweeter s'avère parfait pour les reflexions instantannées, je vous invite donc à me suivre aussi là bas

https://twitter.com/guillaume_agile

 

et ici, toujours des articles de fond et/ou pratiques ; comme le prochain sur le Test avec Asp.Net MVC

Le programme de NEPTUNE'2010 est maintenant disponible, a noter que cette année cet évènement se déroule en collaboration avec ERTS'2010 les 18 et 19 mai..

Le programme de la certification SysML commence à se mettre en place :

OMG Certified Systems Modeling Professional (OCSMP)

Il y aura 4 niveaux. Un beta-programme est maintenant planifié :

OCSMP Model User - April to May 2010
OCSMP Model Builder - Fundamental - June to July 2010
OCSMP Model Builder - Intermediate - July to September 2010
OCSMP Model Builder - Advanced - September to October 2010

1 2 3 4 5 6 7 8 9 10 11 ... 66 >>

Search

Categories

DotNetGuru Weblogs

Potash Valley

Le blog de L'ami S'ami

Bruno Boucard

Julien Brunet

Thibaut Barrère / LoGeek

Laurent Desmons

SyncLock(Me)

Nicolas Torrent

Patrick Smacchia

Chroniques d'Améthyste

Guillaume Saint Etienne 's Blog

Cédric Bonnot

Alain Metge

Bruno Baia

Sylvain Berthu

Le blog d'UmlGuru

Olivier Dabrowski

Business Intelligence ART - Renaud Harduin WebLog

Nicolas Louis

Sébastien Andreo

Blog de Arnaud Fontaine

Blog de Rochdi Chakroun

Guillaume Stritmatter

Eric Groise

Blog#9

Nicolas Penin

Ce qui se conçoit bien s'énonce clairement ... (N.Boileau)

The requested Blog doesn't exist any more!

XML Feeds

blogging software