Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Fathi Bellahcene

.Net m'a tuer!

[Programmez 164] Stratégie & mise en place de Build dans le cloud

 

Dans le magazine programmez de ce mois, j’ai eu l’occasion d’écrire un article sur la mise en place de Build dans le cloud mais surtout quelle stratégie adopter pour mettre en place des Builds.

En effet, les Builds sont un outils incontournable dans la réalisation de logiciel . Nous rappellons donc les différents types de Builds (Integration COntinue, Nightly Build,…) et comment les utiliser de manière optimale.

 

programmez 164 mise en place de builds

 

J’aurais, l’occasion de revenir sur ce sujet dans ce blog!

Livre Blanc : Développer des applications NUI

 

Avec certains de mes collègues de Cellenza, nous avons publié les premiers chapitres d’un livre blanc sur le développement d’application NUI (comprendre window 8).

Vous le trouverez en téléchargement ici et il sera régulièrement mis à jour.

Dans ce livre, nous allons parler des spécificités liée aux applications Windows 8 (les API, le stockage, les états de l’applications,…) les bonnes pratiques de développement (l’industrialisation, l’utilisation de TFS, les tests,…) mais aussi les aspects liés à la publication sur le store Windows 8.

Je vous tiendrais au courant à chaque publication d’un chapitre!

[WebCast]: Application Legacy Testez les avec VS 2012 sans modifier leurs architectures

 

Microsoft viens de mettre en ligne un webcast que j’ai réalisé au sujet des applications légacy. C’est un sujet qui est de plus en plus d’actualité car .NET, qui reste un langage jeune, commence a avoir un parc d’applications conséquent qu’il faut maintenir ou faire évoluer.

c’est également un sujet que j’ai tenté de traiter dans ce blog a travers une série de blog-posts toujours en cours et que je pense finir rapidement.

 

Je vous met donc le liens sur le site MS :

http://www.microsoft.com/france/visual-studio/bonapp/hub-emission.aspx

c’est classé sous le thème Plateforme.

 

Sinon vous avez la possibilité de la voir directement ici:

http://www.microsoft.com/showcase/video.aspx?uuid=7f61ef89-0445-45e3-bbb1-3030d94cbea2

One more year !

 

 

image

Microsoft Fakes guide

l’équipe des ALM Rangers ont récemment publié  un guide de bonnes pratiques pour les tests unitaires et spécialement l’utilisation du Fakes Framework.

Ce qui est sympa, c’est qu’ils ont également livrés des Labs.

Vous pourrez télécharger le guide et les labs ici : http://vsartesttoolingguide.codeplex.com/releases/view/102290

Et, cerise sur le gâteau, vous avez la possibilité de trouver plein d’autres guides concernant les Tests et les outils de manière plus générale (Coded UI, intéllitrace, Test Manager,…)  ici :

http://vsartesttoolingguide.codeplex.com/

 

Bonne lecture!

[Programmez 160]: Article sur le Fakes Framework!

 

Dans le numéro de janvier (160) j’ai publié avec Jason un article sur les Shims: après avoir écris un article sur les nouveautés qu’apporte VS 2012 pour les tests unitaire, il était important pour moi de traiter le Fakes Framework dans un article à part.

 

 

Vous trouverez ici et ici l’article en basse résolution.

[Fakes Framework] : Comment tester unitairement le code Legacy Part 3/4

Dans cette série de trois  4 posts, on a tenté de tester unitairement et améliorer du code legacy de manière totalement safe.

J’ai préféré faire quatre posts plutôt que trois pour qu’ils ne soient pas trop long.

L’idée étant de suivre les étapes suivantes:

  1. tester unitairement le code légacy avec les Shims sans toucher le code.
  2. rendre clean le code sans toucher aux tests.
  3. supprimer les Shims par des Stubs.

Pour faire simple: on ne modifie qu’une chose à la fois pour être sûr de ne pas introduire de régression.

vous trouverez les premières parties ici et ici.

On va donc dans cette partie refactorer le code sans toucher aux tests.

Lorsque je fais du refactoring, j’utilises en général les principes SOLID comme référence. Dans notre cas, on peut tout de suite dire que le code de la classe MainWindow présente pas mal de problème.

Tout d’abord avec le principe SRP : le code de chargement du contenu du fichier n’a rien à faire dans le cette classe qui à pour charge la gestion de l’interface. On va donc sortir ce code dans une autre classe qui aura pour tâche le chargement du contenu à afficher:

Notre classe MainWindow devient donc:

   1: public partial class MainWindow : Window
   2:   {
   3:       private ContentReader _contentReader;
   4:  
   5:       public MainWindow()
   6:       {
   7:           _contentReader= new ContentReader();
   8:           InitializeComponent();
   9:       }
  10:  
  11:       private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
  12:       {
  13:  
  14:           TxtFileContent.Text = GetFileContent();
  15:  
  16:       }
  17:  
  18:       public string GetFileContent()
  19:       {
  20:           return _contentReader.GetFileContent();
  21:       }
  22:  
  23:   }
 
Je ne supprime pas la méthode GetFileContent car je ne souhaite pas modifier mes tests: modifier mes tests reviendrait à ne pas respecter ma stratégie…même si dans ce cas, la modification est safe.

Et notre nouvel classe ContentReader:

 

   1: public class ContentReader 
   2:    {
   3:        private FileNameValidator _fileNameValidator;
   4:        public ContentReader()
   5:        {
   6:            _fileNameValidator = new FileNameValidator();
   7:        }
   8:  
   9:        public string GetFileContent()
  10:        {
  11:            var fileName = ConfigurationManager.AppSettings["fileName"];
  12:  
  13:            if (!_fileNameValidator.IsValid(fileName))
  14:                throw new SettingsPropertyNotFoundException(
  15:                                 "filename format not valid!");
  16:  
  17:            if (!File.Exists(fileName))
  18:                throw new FileNotFoundException("file not found!");
  19:  
  20:            var text = File.ReadAllText(fileName);
  21:            text = string.Format("Le fichier contient le text suivant:
  22:                                              {0}", text.ToUpper());
  23:  
  24:            return text;
  25:        }
  26:    }

 

Ensuit le principe DIP : certes notre classe MainWindow n’est plus en charge de la lecture du fichier, mais si demain je souhaite charger mes données depuis un service ou un fichier xml… ca va pas le faire:

On va introduire une interface IContentReader que notre classe ContentReader va implémenter. On va également la renommer en FileContentReader pour bien préciser que cette classe lit du contenu depuis un fichier:

   1: public interface IContentReader
   2: {
   3:     string GetFileContent();
   4: }
   5:  
   6: public class FileContentReader :IContentReader

Et ensuite on va utiliser cette interface dans la classe MainWindow: si je souhaite utiliser une autre source de données; je n’ai qu’a produire une classe WebServiceContentReader que j’injecte à ma classe MainWindows:

 

   1: public partial class MainWindow : Window
   2: {
   3:     private IContentReader _contentReader;
   4:  
   5:  
   6:     public MainWindow()
   7:         :this(new FileContentReader())
   8:     {
   9:         
  10:     }
  11:     public MainWindow(IContentReader contentReader)
  12:     {
  13:         _contentReader = contentReader;
  14:         InitializeComponent();
  15:     }
  16:  
  17:  
  18:  
  19:     private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
  20:     {
  21:  
  22:         TxtFileContent.Text = GetFileContent();
  23:  
  24:     }
  25:  
  26:     public string GetFileContent()
  27:     {
  28:         return _contentReader.GetFileContent();
  29:     }
  30:  
  31: }

J’ai également deux constructeurs; un sans paramètre qui dit que mon ContentReader par defaut est de type FileContentReader.

Je recompile et rejoues mes tests…et tout est toujours vert!

image

 

On va également appliquer ce principe pour découpler notre classe FileContentReader de la classe FileNameValidator:

On ajoutes une interface IFileNameValidator pour abstraire la relation entre nos deux classes :

   1: public interface  IFileNameValidator
   2: {
   3:     bool IsValid(string fileName);
   4: }
   5:  
   6: public class FileNameValidator : IFileNameValidator 
   7: {
   8:     public bool IsValid(string fileName)
   9:     {
  10:         return !string.IsNullOrEmpty(fileName)
  11:                     && fileName.Length > 2;
  12:     }
  13: }

et pour la classe FileContentReader:

   1: public class FileContentReader :IContentReader
   2: {
   3:     private IFileNameValidator _fileNameValidator;
   4:  
   5:     public FileContentReader()
   6:         :this(new FileNameValidator())
   7:     {
   8:         
   9:     }
  10:  
  11:     public FileContentReader(IFileNameValidator fileNameValidator)
  12:     {
  13:         _fileNameValidator = fileNameValidator;
  14:     }
  15:  
  16:     public string GetFileContent()
  17:     {
  18:         var fileName = ConfigurationManager.AppSettings["fileName"];
  19:  
  20:         if (!_fileNameValidator.IsValid(fileName))
  21:             throw new SettingsPropertyNotFoundException(
  22: "filename format not valid!");
  23:  
  24:         if (!File.Exists(fileName))
  25:             throw new FileNotFoundException("file not found!");
  26:  
  27:         var text = File.ReadAllText(fileName);
  28:         text = string.Format("Le fichier contient le text suivant:
  29:                      {0}", text.ToUpper());
  30:  
  31:         return text;
  32:     }
  33: }

Pour la classe configurationManager, on va passer par une interface + une classe proxy:

   1: public interface IConfigurationService
   2: {
   3:     string GetValue(string key);
   4: }
   5:  
   6: public class ConfigurationService : IConfigurationService
   7: {
   8:     public string GetValue(string key)
   9:     {
  10:         return ConfigurationManager.AppSettings[key];
  11:     }
  12:  
  13: }

Et pour ma classe FileContentReader:

 

   1: public class FileContentReader :IContentReader
   2:  {
   3:      private IFileNameValidator _fileNameValidator;
   4:      private readonly IConfigurationService _configurationService;
   5:  
   6:      public FileContentReader()
   7:          :this(new FileNameValidator(), new ConfigurationService())
   8:      {
   9:          
  10:      }
  11:  
  12:      public FileContentReader(IFileNameValidator fileNameValidator , 
  13: IConfigurationService configurationService)
  14:      {
  15:          _fileNameValidator = fileNameValidator;
  16:          _configurationService = configurationService;
  17:      }
  18:  
  19:      public string GetFileContent()
  20:      {
  21:          var fileName = _configurationService.GetValue("fileName");
  22:  
  23:          if (!_fileNameValidator.IsValid(fileName))
  24:              throw new SettingsPropertyNotFoundException(
  25: "filename format not valid!");
  26:  
  27:          if (!File.Exists(fileName))
  28:              throw new FileNotFoundException("file not found!");
  29:  
  30:          var text = File.ReadAllText(fileName);
  31:          text = string.Format("Le fichier contient le text suivant
  32: : {0}", text.ToUpper());
  33:  
  34:          return text;
  35:      }
  36:  }

 

Je recompile le tout et rejoue mes test que je n’ai pas modifiés…et tout est encore vert!

Au final, notre méthode à tester n’est plus couplé qu’a la classe File du framework .net. Ici, je préfère ne pas découpler cette classe: je suis dans une classe spécialisée dans la manipulation de ficher et j’ai déjà une couche d’abstraction (l’interface IContentReader). Dans ce cas précis, et d’un point de vue strictement “design” je ne trouve donc pas choquant le couplage. Découpler ici n’est utile que pour la testabilité de notre méthode (mais ca, avec le Fakes Framework c’a n’est plus un problème).

Cela est très important car très souvent on fait des choses avec lesquelles on est mal à l’aise mais on a pas le choix si on souhaite avoir une grosse couverture de code: c’est de l’”over design” directement liées aux framework de Mocks que l’on utilise. Avec le Fakes framework, on a la possibilité d’avoir un design a son gout sans être influencé par l’écriture des tests unitaires.

On peut bien évidement aller encore plus loin dans le refactoring de cette petite aplication avec pour objectif, par exemple, le pattern MVVM

On a donc :

  1. ajouter des tests unitaires sans modifier le code legacy…mais avec des Shims (qui sont mauvais) et le code est toujours de mauvaise qualité.
  2. améliorer le code sans modifier les tests…mais qui contiennent des shims.

Dans la prochaine partie on va introduire les Stubs pour tester notre code sans le modifier, mais cette fois ca sera facile vu qu’il est rendu testable Sourire

ATE sur les Microsoft Tech Days 2013

 

Hello!

J’aurais le plaisir d’être ATE aux techdays 2013 à Paris les 13 et 14 février prochain. Ca sera l’occasion pour moi d’échanger en live avec vous !

 

image001

 

Au plaisir de vous voir !

[Fakes Framework] : Comment tester unitairement le code Legacy Part 2/4

 

Vous trouverez la première partie ici.

On doit bien garder en tête notre stratégie: intégrer des tests avec les Shims sans toucher au code existant, le re-factorer pour améliorer sa qualité et ensuite remplacer les Shims par des Stubs.

Dans cette partie, on va:

  1. présenter l’exemple que l’on va tenter de tester.
  2. présenter le system under test (SUT) et les couplages que nous allons traiter avec le Fakes Framework.
  3. Définir les scénarï de tests et isoler le SUT sans modifier le code existant avec les Shims.

 

l’exemple:

Trouver un exemple ne fut pas un chose simple: je devais trouver quelque chose de simple à expliquer, accessible à tous mais qui doit montrer les principaux problèmes rencontrés dans la vraie vie et tout ca en très peu de lignes de code.

il existe plusieurs problèmes qui rendent un code non testable ou difficilement testable, mais le problème qui à mon avis est le plus important c’est le couplage.

il existe plusieurs types de couplages (comprendre plusieurs types d’objets avec lesquelles notre système à tester est couplé). J’ai donc choisis d’en montrer quelques uns :

  • le couplage liée à la construction de l’objet: pour tester une méthode, encore faut-il construire un objet et on est donc obligatoirement dépendant de tout ce qui est nécessaire à la construction de notre objet…utile ou pas.
  • le couplage standard sur des classes externes: notre système à tester (SUT) fait appel à une classe externe pour sous traiter une partie du traitement.
  • le couplage avec des classes/méthodes statiques et donc quelque part avec des singleton, des factory… : un grand débat entre architectes puristes du GoF vs puristes du TDD.

Je vous propose donc l’application suivante :

une petite application WPF qui va récupérer dans le fichier de config le chemin complet d’un fichier, ensuite elle va faire quelques vérification sur ce fichier et en afficher le contenu mis en forme.

le fichier de config est le suivant:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
    <SupportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>

  <appSettings>
    <add key="fileName" value="c:\test\DemoFakesFramework.txt"/>
  </appSettings>
</configuration>

le fichier contient le texte suivant: “Fakes Framework Demo!”

Graphiquement cela donne (après chargement du fichier) :image

Et le code du bestiaux:

   public partial class MainWindow : Window
    {
        public FileNameValidator FileNameValidator { get; set; }
        
        public MainWindow()
        {
            InitializeComponent();
            FileNameValidator = new FileNameValidator();

        }


        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
           TxtFileContent.Text  = GetFileContent();
        }

        public string GetFileContent()
        {
            var fileName = ConfigurationManager.AppSettings["fileName"];


            if (!FileNameValidator.IsValid(fileName))
                throw new SettingsPropertyNotFoundException("pas de param!");

            if (!File.Exists(fileName))
                throw new FileNotFoundException("pas de fichier!");

            var text = File.ReadAllText(fileName);
            text = string.Format("Le fichier contient le texte suivant: {0}",
                                     text.ToUpper());

            return text;
        }
    }
 
la classe en charge de valider le nom du fichier est très simple:
 
    public class FileNameValidator
    {

        public bool IsValid(string fileName)
        {
            return !string.IsNullOrEmpty(fileName) 
                        && fileName.Length>2;
        }
    }

Elle se contente de vérifier que le nom n’est pas nul et qu’il contient plus de deux caractères.

Rien de bien compliqué: tout le traitement est fait dans la méthode GetFileContent, on récupère le paramètre dans le fichier de config, on le valide et on charge le contenu du fichier en majuscule dans une variable auquel on ajoute “Le fichier contient le texte suivant” au début et que l’on renvoi dans la foulée.

SUT & couplages

Le SUT est la méthode GetFileContent dont on a expliqué le fonctionnement ci-dessus.

on va donc recenser les différents couplage que nous devrons adresser avec le Fakes Framework pour savoir quelles sont les Fakes assemblies que nous allons avoir à générer.

On a donc un couplage avec :

  • la méthode InitializeComponent() qui se trouve dans le constructeur et qui n’est pas utile pour notre SUT.Elle se trouve dans la même assembly que notre SUT on aura donc aucune Fakes Assembly à générer de plus.
  • La classe FileNameValidator utilisée pour valider le nom de notre fichier. Elle se trouve dans la même assembly que notre SUT on aura donc aucune Fakes Assembly à générer de plus.
  • la classe ConfigurationManager pour récupérer la valeur de configuration –> on va devoir générer la Fakes Assembly pour System.Configuration.
  • la classe File pour valider la présence du fichier et lire son contenu –> on va devoir générer une Fakes Assembly pour System.dll (qui contient System.IO).

On va donc devoir génerer des Fakes pour les assemblies suivantes:

  • WpfApplication1 (celle contenant notre application)
  • System.Configuration.dll
  • System.dll

la génération des Fakes assemblies se fait très simplement et a  été présenté dans des posts précédents.

Les Shims entrent en actions!

On identifie aussi trois scénarios de tests pour être sûr que notre méthode fonctionne bien. Pour chacun d’entre eux, nous allons créer le test unitaire permettant de s’assurer qu’il est bien respecté.

  • La clé de configuration n’existe pas ou est nulle. Dans ce cas, on doit avoir une exception de type SettingsPropertyNotFoundException.
  • le fichier n’existe pas. on doit avoir une exception de type FileNotFoundException.
  • Le fichier existe et tout est ok: la clé de config est bonne et le fichier existe bien. On s’assure également que le text renvoyé est correctement formaté.

Avec ces trois tests, on doit avoir une couverture de code maximale pour notre SUT. Bien évidement, on ne doit en aucun cas toucher au code existant car on ne maitrise pas les effets de ces modifications avec du code Legacy.

Test 1: La clé de config est mauvaise

On va devoir utiliser les Shims pour tout ce qui est utiliser avant la validation du nom du fichier: le constructeur (du moins la partie InitialiseComponent et la classe FileNameValidator):

 

        [TestMethod]
        [ExpectedException(typeof(SettingsPropertyNotFoundException))]
        public void ConfigKeyIsEmpty()
        {

            using (ShimsContext.Create())
            {

                ShimMainWindow.AllInstances.InitializeComponent = 
                           window => { };
                ShimConfigurationManager.AppSettingsGet = () =>
                {
                    var dictionary = new NameValueCollection() { };
                    dictionary.Add("fileName", "filenameisOK");

                    return dictionary;
                };
                ShimFileNameValidator.AllInstances.IsValidString = 
                          (validator, s) => false;
                

                var mw = new MainWindow();
                mw.GetFileContent();

            }
        }

Pour rappel, on utilise la classe ShimsContext pour délimiter un block dans lequel les shims seront opérationnels: dans ce block, tout appel à une méthode redéfinie par un Shims sera intercepté et redirigé. il est donc très important de TOUJOURS utiliser un block using pour éviter des interférences entres les différents tests.

Je commence par redéfinir la méthode InitializeComponent: celle-ci fait appel à du code géneré servant uniquement la partie graphique: il n’est donc pas utile de l’avoir dans notre code (nous ne sommes même pas sûr que cela fonctionne dans un test unitaire). je l’a remplace par une méthode qui ne fait rien:

ShimMainWindow.AllInstances.InitializeComponent = window => { };

ensuite, je remplace l’appel au dictionnaire (singleton) AppSettings qui se trouvent dans la classe ConfigurationManager. je le remplace par un dictionnaire contenant une seul entrée  : “fileName” avec la valeur “filenameisOK”.

ShimConfigurationManager.AppSettingsGet = () => { var dictionary = new NameValueCollection() { }; dictionary.Add("fileName", "filenameisOK"); return dictionary; };

Si on exécute le code de validation pour cette valeur, celle-ci est bonne (non nulle et plus de deux caractères) mais on va également redéfinir la méthode IsValid pour que celle-ci renvoi toujours false: ce qui correspond à notre scénario de test:

ShimFileNameValidator.AllInstances.IsValidString = 
                          (validator, s) => false;

Si j’exécute le tests, j’obtiens bien une exception de type

SettingsPropertyNotFoundException: nous avons fini notre premier test!

 
test 2 : Le fichier n’existe pas
Nous allons reprendre le premier test avec quelques modification: tout d’abord le nom 
de fichier sera valide et ensuite et ensuite nous signifierons au SUT qu’il n’existe pas: Pour cela, 
nous allons utiliser un Shims sur la classe File.
  [TestMethod]
        [ExpectedException(typeof(FileNotFoundException))]
        public void FileNotExist()
        {

            using (ShimsContext.Create())
            {


                ShimMainWindow.AllInstances.InitializeComponent =
                       window => { }; 
                ShimConfigurationManager.AppSettingsGet = () =>
                {
                    var dictionary = new NameValueCollection() { };
                    dictionary.Add("fileName", "");

                    return dictionary;
                };
                ShimFileNameValidator.AllInstances.IsValidString = 
                          (validator, s) => true;

                ShimFile.ExistsString = s => false ;
 

                var mw = new MainWindow();
                mw.GetFileContent();

            }
        }
Test 3 : Tout est ok!
on reprend le test pécédent et on dit que le fichier existe, qu’il nous renvoi une valeur (via le 
Shims sur la classe File) et on vérifie le formatage :
 
 [TestMethod]
        public void FileExistAndConfigExist()
        {

            using (ShimsContext.Create())
            {


                ShimMainWindow.AllInstances.InitializeComponent =
                                       window => { };
                ShimConfigurationManager.AppSettingsGet = () =>
                   {
                      var dictionary = new NameValueCollection() {};
                      dictionary.Add("fileName", "");
                      return dictionary;
                    };

                ShimFileNameValidator.AllInstances.IsValidString = 
                              (@this,s) => true;

                ShimFile.ExistsString = s => true; 
                ShimFile.ReadAllTextString = s => "Fake content";


                var mw = new MainWindow();
                var calculatedValue = mw.GetFileContent();
                

                string retVal = "Le fichier contient le text suivant: "
                                  + "FAKE CONTENT";

                Assert.AreEqual(retVal, calculatedValue);

            }
        }

On exécute tout ca depuis VS 2012 et on obtient :

image
Des tests verts sans avoir modifié le code existant et…
image
 

un SUT couvert à 100%! le compte est bon!! Rendez-vous pour la partie la plus interresante de cette série de posts: la refactorisation du code et le remplacement des Shims par des Stubs.

[Fakes Framework] : Comment tester unitairement le code Legacy Part 1/4

 

Le “Fakes Framework”

Cela fait quelques temps que je regarde le Fakes Framework sous tous ses angles et je doit dire que je suis passé par plusieurs états:

Tout d’abord, j’étais très enthousiaste : les Shims apportaient une réel plus value par rapport aux framework existant (MoQ et  RhinoMock par exemple). On avait la possibilité de produire du code avec le design que l’on voulait sans être contraint par l’écriture des tests unitaires.

Ensuite, un peu de déception: l’utilisation de préfixe (Shims & Stubs) et de suffixe (les types des params) éloignent l’écriture des tests du code métier. le fait que les classes soient générées rend le réfactoring pénible car on doit tout régénérés à chaque modification. Sans oublier que le temps de compilation est rallongé. La puissance des Shims mis dans les mains de développeurs pas sensible à la qualité du design ne m’enchante gère: on va pouvoir faire du code crade ET le tester : on perd donc un des aspects positif (et certainement le plus important) du TDD qui est justement de forcer les développeurs à respecter un certains nombre de bonnes pratiques: des méthodes courtes et ayant une unique tâche (SRP) des classes découplés (DIP), l’utilisation d’interfaces (IBP)…

Pour résumer en une phrase:

Un grand pouvoir implique de grandes responsabilités

A partir de là, je me suis poser la question suivante: comment utiliser proprement le Fakes Framework lorsque l’on doit traiter du code Legacy.

Pourquoi cette question?

  • Il ne faut pas se voiler la face : la majorité du code que j’ai rencontré dans ma vie n’est pas (ou très peu) testé. Le TDD ne s’applique pas et je n’ai pas connaissance d’une méthode permettant de traiter le code Legacy.
  • Parce qu'avec l’arrivé des méthodes Agile, faire du développement qui implique d’accepter le changement donc de supporter de gros refactoring doit être testé (sinon c’est la catastrophe assuré)
  • Parce que je reste persuadé que le Fakes Framework est un formidable outil qui est en mesure de traiter ces problèmes et qu’il ne reste plus qu’a trouver la bonne méthode: on ne doit pas jetter le bébé avec l’eau du bain.

Quel est le problème posé par le code Legacy?

On pourrait définir le code Legacy de la manière suivante:

Un code crade, peu documenté, pas testé, fait par des développeurs qui ne sont plus présent dans la société et qui n’a pas de specs à jours….MAIS qui fonctionne!

Donc, si on souhaite le tester, on doit d'abord le modifier pour le rendre testable(réduire la taille des méthodes, casser le couplage,… ) mais si on fait ca, on risque d’introduire des bugs sans s’en rendre compte car on a pas de tests unitaires pour s’assurer que l’on ne casse rien.

C’est donc le serpent qui se mord la queue:

 

Le “Fakes Framework” permet une approche qui pourrait résoudre ce problème, en combinant les nouvelles possibilités offertes par les Shims avec les Stubs. Ca donnerai ca:

  1. On utilise les Shims pour tester sans modifier le code Legacy jusqu’a ce qu’il soit totalement couvert.
  2. On ré-factorise le code Legacy avec la garantie que l’on n’introduit pas de bugs car on a des tests unitaires
  3. On remplace les Shims par des Stubs: parce que les Shims c’est dangereux et que tant qu’il nous reste des Shims, on a potentiellement des défaut de design dans notre programme.
  4. une fois tout nos Shims supprimés: on se retrouve dans une situation proche de celle qu’apporte le TDD : code testé ET de qualité.

Alors bien sûr, la théorie c’est bien beau mais ca donne quoi concrètement? Je vous propose donc d’appliquer cette méthode sur un exemple et de voir avec vous ce que cela donne.

 

A suivre…

Vous aurez donc deux blog-post avec les contenu suivant:

Part 2/3 : Présentation de l’exemple et appliquation des Shims

Part 3/3 : Refactoring et application des Stubs et conclusion

 

@Bientôt!

[Fun] Introduction à VS 2012

 

J’ai vu cette vidéo que j’ai trouvé drôle et sympa sur la forme. Elle met en avant quelques features de VS2012 (ultimate) de manière assez rapide et fun.

Article Programmez 157 : PCL avec VS 2012

Avec Jason, nous avons publié un article dans le magazine Programmez (157- Novembre) sur l’utilisation de PCL “Portable Class Library”.

couverture

Avec l’arrivée de Windows 8, Surface, Windows Phone 8…l’utilisation de composant multiplateforme devient incontournable et avec PCL, Microsoft adresse admirablement cette problématique!

TDD avec Visual Studio 2012 : Part 3/3

Je vous propose de partager avec vous cet article grandement inspiré de l’article publié dans le magazine Programmez et écrit avec Jason De Oliveira. Je tiens également à préciser que le but de cet article est surtout de montrer qu’avec les nouveautés apportés dans Visual Studio 2012, l’application du TDD quelque soit la technologie et le framework de test que l’on souhaite utiliser est grandement facilité.

Je vais donc faire trois posts avec les thèmes suivants:

Part 1: rappel sur le TDD + Nouveautés

Part 2 : (Nouveautés fin) + Améliorations ergonomique

Part 3 : Exemple d’application du TDD

Part 3/3:

Prenons un exemple concret dans Visual Studio 2012 pour implémenter des fonctionnalités d’un calculateur.

Phase 1: Ecriture du premier test pour une nouvelle fonctionnalité

En respectant le Test Driven Development, il faut d’abord créer les tests unitaires pour les méthodes « Addition » et « Multiplication ». Pour cela, il faut ajouter un nouveau projet de type « Unit Test Project » :

Fig8_UniTestProject

Voici un exemple d’implémentation des tests unitaires en utilisant NUnit :

    [TestFixture]
    public class UnitTests
    {

        [Test]
        public void Calculator_AdditionTest()
        {
            var calculator = new Calculator();
            Assert.AreEqual(calculator.Addition(2, 3), 5);
        }

        [Test]
        public void Calculator_MultiplicationTest()
        {
            var calculator = new Calculator();
            Assert.AreEqual(calculator.Multiplication(2, 3), 6);
        }

    }

A noter que la définition de la classe « Calculator » et de ses méthodes « Addition » et « Multiplication » n’existent pas encore à ce stade.

Visual Studio 2012 permet la génération du code manquant de manière automatique. Pour cela, il faut cliquer droit sur la définition « new Calculator » dans le projet de tests unitaires et choisir de générer la classe via l’option « Generate/New Type ». Un assistant s’ouvre permettant de configurer le type (classe, struct, interface, enum), l’accès (public, internal), le projet de destination et le nom du fichier pour la création de la classe manquante. L’étape suivante consiste donc à générer automatiquement les méthodes manquantes au sein de la nouvelle classe « Calculator ». Ceci se fait quasiment de la même manière, en cliquant droit sur les appels « calculator.Addition(…) » et « calculator.Multiplication(…) » dans le projet de tests unitaires et en choisissant « Generate/Method Stub ».

Voici ce qui est généré :

 public class Calculator
    {
        public object Addition(int i, int i1)
        {
            throw new NotImplementedException();
        }

        public object Multiplication(int i, int i1)
        {
            throw new NotImplementedException();
        }
    }

La dernière étape de cette phase comporte le lancement de « Test Explorer » et l’exécution de tous les tests unitaires via « Run All » (ou utiliser l’option d’exécution des tests unitaires après compilation). Comme attendu, les tests échouent car l’implémentation du code n’a pas encore été faite :

Fig11_FailedTests

Phase 2: Implémentation du code minimal nécessaire pour passer le test

Il ne reste plus qu’à écrire le code qui implémente les fonctionnalités attendues. L’idée est de programmer le code le plus simple répondant aux besoins. L’optimisation et l’amélioration interviennent dans un deuxième temps dans la phase suivante (la refactorisation).

  public class Calculator
    {
        public int Addition(int value1, int value2)
        {
            return value1 + value2;
        }

        public int Multiplication(int value1, int value2)
        {
            return value1 * value2;
        }

    }

Suite à l’implémentation, il faut alors relancer « Test Explorer » et exécuter tous les tests unitaires via « Run All » (ou utiliser l’option d’exécution des tests unitaires après compilation) et valider que les tests passent avec succès :

Fig12_PassedTests

A ce stade-là, le code répond aux besoins attendus. La structure finale inclut un projet avec l’implémentation et un autre avec tous les tests unitaires. Par contre, le code n’est peut-être pas optimisé et sa qualité peut laisser à désirer. Il va falloir donc l’améliorer. Les tests unitaires servent dans ce cas comme filet de sauvetage : la refactorisation du code peut se faire sans avoir peur des régressions, car celles-ci seront détectées par les tests unitaires.

Phase 3: Refactorisation et optimisation du code

La refactorisation décrit le processus d’amélioration de code après son écriture en modifiant sa structure interne sans modifier son comportement extérieur. On transforme un code qui fonctionne en un code qui fonctionne de manière optimale. Souvent, il en résulte un code plus rapide, utilisant moins de mémoire ou simplement présentant une implémentation plus élégante.

Cela consiste à :

· Détecter et éliminer toute duplication de code

· Limiter la complexité et le nombre de classes

· Simplifier et optimiser l'algorithmique des méthodes

· Relocaliser, renommer et harmoniser les méthodes

· Améliorer la lisibilité du code

· Supprimer le code non utilisé (dit code mort)

· Ajouter des commentaires sur des sections complexes

Dans l’exemple, il n’y a rien à refactoriser, car il n’y a pas encore beaucoup de méthodes ni de classes implémentées. Cette dernière étape doit quand même être réalisée en fin de chaque itération du cycle. Le cycle incluant d’autres fonctionnalités recommence ensuite depuis la phase 1.

Conclusion:

Microsoft à fait un grand pas vers le support des méthodes agiles avec Tfs et Visual Studio 2012. Les améliorations ergonomiques et les nouveautés apportés a la gestion des tests unitaires est un grand pas en avant et les developpeurs n’auront plus beaucoup d’excuse pour ne pas adopter le TDD. De plus cette vversion de visual studio cache un véritable trésor qui est  le “fakes framework” car il va nous permettre de tester du code légacy en toute simplicité sans avoir à retoucher le code ce qui est une réel nouveauté dans l’échosysteme .NET, on regrettera simplement qu’il ne soit disponible qu’avec la version Ultimate.

TDD avec Visual Studio 2012 : Part2/3

Je vous propose de partager avec vous cet article grandement inspiré de l’article publié dans le magazine Programmez et écrit avec Jason De Oliveira. Je tiens également à préciser que le but de cet article est surtout de montrer qu’avec les nouveautés apportés dans Visual Studio 2012, l’application du TDD quelque soit la technologie et le framework de test que l’on souhaite utiliser est grandement facilité.

Je vais donc faire trois posts avec les thèmes suivants:

Part 1: rappel sur le TDD + Nouveautés

Part 2 : (Nouveautés fin) + Améliorations ergonomique

Part 3 : Exemple d’application du TDD

 

Part 2/3:

 

Fakes Framework (Stubs et Shims)

Visual Studio 2012 a également intégré le « Fakes Framework » issu du projet « Moles » créé­­ par l’équipe Microsoft Research. Ce framework sera disponible uniquement avec la version Ultimate de Visual Studio 2012.

Le but de cet outil est de permettre aux équipes de développement de produire rapidement et facilement des tests unitaires. Pour cela, le « Fakes Framework » introduit deux notions :

· Les Stubs : ce sont des implémentations d’interfaces ou de classes abstraites automatiques pouvant être utilisées par les tests afin d’isoler la partie à tester unitairement.

· Les Shims : ce sont des mécanismes qui interceptent des appels de méthodes au run-time et les remplacent par d’autres. Les Shims peuvent être utilisés pour isoler les appels vers des méthodes contenues dans des objets qui ne peuvent normalement pas être « mockés ». Par exemple, il est impossible de tester unitairement des méthodes faisant appel à certains objets du framework .NET. Grâce aux Shims, il est possible de rediriger les appels vers ses propres implémentations.

Les classes du framework .NET incluses dans les namespaces « mscorlib » et « system » ne peuvent pas avoir de « Fake Assembly ». On ne pourra donc malheureusement pas créer de Shims pour la classe « System.Configuration.ConfigurationManager » par exemple.

Le « Fakes Framework » apportent un réel plus par rapport à des framework de tests existants (comme RhinoMock) qui poussent souvent les développeurs à modifier leur code fonctionnel pour pouvoir effectuer des tests unitaires.

Vous trouverez également un post dans mon blog à ce sujet ici

Gestion des tests via Test Explorer

La première impression à l’ouverture de la fenêtre « Test Explorer » est très positive. Voici les principaux changements apportés :

· Les panneaux « Test View » et « Test Results » ont été supprimés et remplacés par le « Test Explorer », ceci améliore l’interaction entre le développement (le code) et les tests.

· L’interface est simple mais efficace : toutes les informations sont accessibles par simple clic de la souris de manière parfaitement intuitive.

· Les tests sont regroupés en fonction de leur statut (failed, passed,…) et les premiers tests visibles sont ceux en échec : ceux qui intéressent en priorité les développeurs. De plus, il n’y a plus besoin de passer par le panneau « Test Results » pour accéder aux sources du test, un simple double clic permet d’atteindre les sources. On regrettera au passage que les tests ne peuvent toujours pas s’afficher sous forme hiérarchique.

· L’exécution de l’analyse de la couverture du code est simplifiée. Dans les versions précédentes, lancer une couverture de test était certes simple mais pas très intuitif : vous deviez créer un fichier de configuration, le configurer, le lancer depuis le menu Visual Studio et ouvrir la fenêtre adéquate pour obtenir le résultat. Avec Visual Studio 2012, tout cela est plus facile car tout est intégré dans l’interface du « Test Explorer ». Le lancement d’une analyse de la couverture du code se fait directement avec la souris.

Post Build Test Runs

Une bonne habitude à adopter lors de l’application du TDD est d’exécuter les tests unitaires le plus souvent possible pour s’apercevoir au plus tôt d’un dysfonctionnement ou d’une éventuelle régression. Il existe dans la nouvelle version de Visual Studio 2012 la possibilité d’activer l’exécution des tests unitaires après chaque compilation. Ceci est disponible dans le menu « Test/Test Settings » :

Fig7_RunTestsAfterBuild

Mais aussi directement depuis le « Test Explorer ». De plus, les tests unitaires tournent sur un Thread d’arrière-plan, la productivité des développeurs n’étant donc pas impactée.

Compatibilité ascendante entre Visual Studio 2010 et Visual Studio 2012

Ceux qui, comme nous, ont déjà effectué la migration des tests unitaires de Visual Studio 2008 vers Visual Studio 2010, ont pu rencontrer quelques difficultés et quelques bugs car la migration n’était pas transparente et parfois complexe. Cette opération était fort pénible, dans certains cas, la migration des applications devait même être forcée vers le framework .NET 4.0 !

Rassurez-vous, avec Visual Studio 2012, vous n’aurez aucun problème de ce type, car les composants utilisés sont les mêmes que ceux utilisés par Visual Studio 2010. En effet, le composant actuel est encore « Microsoft.VisualStudio.QualityTools.unitTestFramework.dll » dans la version 10.0.0.0 et utilise toujours le runtime .NET v2.0.50727.

TDD avec Visual Studio 2012 : Part1/3

Je  vous propose de partager avec vous cet article grandement inspiré de l’article publié dans le magazine Programmez et écrit avec Jason De Oliveira. Je tiens également à préciser que le but de cet article est surtout de montrer qu’avec les nouveautés apportés dans Visual Studio 2012, l’application du TDD quelque soit la technologie et le framework de test que l’on souhaite utiliser est grandement facilité.

Je vais donc faire trois posts avec les thèmes suivants:

Part 1: rappel sur le TDD + Nouveautés

Part 2 : (Nouveautés fin) + Améliorations ergonomique

Part 3 : Exemple d’application du TDD

L’objectif de cet article est d’être pragmatique et orienté projet : nous souhaitons montrer que les nouveautés apportées dans la nouvelle version de Visual Studio 2012 permettront aux développeurs de faciliter et de rendre naturel le développement TDD. Il s’agit également de simplifier et limiter l’intégration des différents outils dans un processus d’intégration continue.

Le Test Driven Development (développement piloté par les tests) décrit une technique de développement de logiciel qui consiste à écrire des tests unitaires avant l'écriture du code source.

Voici les différentes étapes du Test Driven Development :

image

 

  1. Ecriture du premier test pour une nouvelle fonctionnalité puis vérification de l’échec du test (l’implémentation de la nouvelle fonctionnalité n’étant pas encore réalisée)
  2. Implémentation du code minimal nécessaire pour passer le test puis vérification du succès du test (l’implémentation fournit alors le comportement attendu)
  3. Refactorisation et optimisation du code, les tests assurent la cohérence des fonctionnalités

L’utilisation du Test Driven Development permet ainsi l’obtention d’un code source très fiable, prévisible, robuste et, après refactorisation, hautement optimisé. Les tests assurent un comportement correct de celui-ci indépendamment des situations auxquelles il pourra être exposé. Le code source devient alors valide en toutes circonstances.

Pour créer de bons tests unitaires, il faut d’abord réfléchir à la conception du programme et à la façon dont il va être utilisé. Il faut éviter une précipitation dans l'implémentation avant d'avoir défini les objectifs. Des erreurs de conception peuvent ainsi être identifiées et résolues plus vite. L’implémentation passe seulement après la validation de la conception complète via les tests unitaires. Les tests unitaires deviennent une sorte de spécification générale décrivant les fonctionnalités du programme de manière unitaire.

Quant à la refactorisation, l’optimisation et la restructuration du code peuvent se faire sans risque car ils sont vérifiables ; les tests unitaires assurant alors la non-régression technique et la cohérence du comportement. Le comportement étant exprimé dans les tests unitaires, ils valident que le programme se comporte toujours de la même façon si les tests passent avec succès. De plus, en associant la méthode d’Extreme Programming (XP) et la programmation en binôme, on obtient un code de très bonne qualité.

Contrairement à d’autres méthodes où les tests sont abordés en fin du cycle, le Test Driven Development met donc le focus sur les tests dès les premières étapes du cycle de développement. Aucun développement ne peut commencer avant que les tests soient conçus et implémentés. Cette méthode a donc un large impact sur l’organisation de l’équipe de développement.

Support des frameworks de tests dans Visual Studio 2012

Les versions précédentes de Visual Studio permettent l’utilisation d’autres frameworks de tests, mais cela implique certaines limitations comme par exemple :

· L’utilisation d’une application tierce pour jouer les tests unitaires comme avec Gallio : l’utilisation de l’application Icarus Runner est indispensable pour pouvoir exécuter les tests unitaires.

· La couverture de code native ne fonctionne pas sans l’utilisation d’autres plugins (NCover).

· L’exécution des tests unitaires diffère en fonction des plugins : un test utilisant MSTest ne s’exécute pas de la même manière s’il est lancé depuis Visual Studio 2008 ou depuis Resharper, ceci peut poser problème lors de l’utilisation d’un processus d’intégration continue.

Au final avec l’ancienne version de Visual Studio 2010, on finit par multiplier les plugins et les outils pas toujours compatibles les uns avec les autres, ce qui ne permet pas vraiment de tirer avantage des fonctionnalités avancées des frameworks de tests spécialisés.

­Dans un environnement où le nombre de projets est conséquent, on a besoin de pouvoir utiliser un framework de tests plutôt qu’un autre en fonction des spécificités du projet et des fonctionnalités de celui-ci. Il est donc important de pouvoir proposer aux équipes de développement un large choix de frameworks de tests avec un coût d’intégration limité (dans les outils de développement comme dans les outils d’intégration continue).

L’une des belles surprises de cette nouvelle version de Visual Studio est justement le support de plusieurs frameworks de tests unitaires tels que :

Pour .NET :

Pour Javascript/HTML :

Pour C++ :

Prenons, par exemple l’intégration du framework de tests NUnit. Après l’installation de NUnit via NuGet :

image

L’adaptateur de test est téléchargeable sous la forme d’un plugin via le gestionnaire d’extension :

image

Disponible dans le menu « Tools/Extensions and Updates… » de Visual Studio 2012 :

image

Cette fonctionnalité est complètement intégrée à Visual Studio et les adaptateurs de test sont disponibles gratuitement sur internet.

Ensuite, vous pouvez écrire vos tests unitaires en utilisant les fonctionnalités intégrées et les exécuter directement dans Visual Studio 2012. Vous pouvez ainsi obtenir les résultats des tests et d’autres informations comme l’analyse de la couverture du code:

image

Le support des tests unitaires pour les programmes en C++ est également une nouveauté non négligeable. Les développeurs C++ pourront ainsi se mettre au TDD en utilisant les projets de type “MSTest Native'”:

image

 

Voici un exemple d’implémentation des tests unitaires en utilisant C++ et MSTest Native :

image

Support de « async » et « await » dans les tests

Avec l’arrivée du framework .Net 4.5 et surtout de Windows 8, il est évident que la programmation asynchrone est l’une des nouveautés les plus importantes et incontournables ; Visual Studio 2012 et son framework de test unitaire supportent parfaitement cette nouvelle approche.

Les mots clé async et await introduits par .Net 4.5 peuvent désormais être utilisés pour faire des tests unitaires sur des méthodes asynchrones.

Voici un exemple d’une méthode asynchrone à tester :

   1: public async Task<int> AdditionAsync(int value1, int value2)
   2: {
   3:     // Simulate computing time
   4:     await Task.Delay(3000);
   5:     return  value1 + value2;
   6: }

La méthode de test correspondante, implémentée en utilisant NUnit, pourrait être la suivante :

 

   1: [Test]
   2: public async void AdditionAsync_PositiveValues()
   3: {
   4:     var calculator = new Calculator();
   5:     var result = await calculator.AdditionAsync(1, 2);
   6:     Assert.AreEqual(3, result);
   7: }
Article Programmez 155 : TDD avec VS 2012

 

Avec Jason, nous avons publié un article dans le magazine Programmez (155) sur le TDD et VS 2012.

L’idée de cet article n’était pas de faire une contribution majeure sur le TDD (presque tout à été dit sur le sujet et par des personnes beaucoup plus compétentes que nous) mais d’aborder le sujet par le prisme des nouveautés (ou plutôt de la refonte total) apportés à MsTest dans Visual Studio 2012.

Vous trouverez le début de cet article ici et bientôt sur ce blog.

VS 2012 : Portable Class Library

 

Par le passé, j’ai été confronté a une problématique assez courante: je souhaitais faire des devs qui puissent être utilisés aussi bien par des projets “classique” type winform, ASP.NET, WPF mais aussi SilverLight. Cela n’était pas possible simplement étant donnée que ces technologies ne partagent pas le même runtime.

Microsoft apporte une réponse a ce problème dans Visual Studio 2012 avec “les Portable Class Library”: vous aurez donc la possibilité de produire des librairies de composants utilisables par plusieurs types de projets.

Pour cela, rien de plus simple, depuis VS 2012, il vous suffit de creer un nouveau projet de type “Portable Class Library”:

image

Ensuite, de lui renseigner quels sont les frameworks  avec lesquels vous voulez être compatible:

image

 

Bien évidement, il faut viser au plus juste car plus vous allez ajouter des Frameworks, moins vous aurez de features de disponibles lors du développement de votre librairie.

J’ajoute dans ce composant un code d’exemple:

    public class Foo
    {
        public string GetFoo()
        {
            return "Foo";
        }
    }

 

J’ajoute également à ma solution un projet de type librairie SilverLight 5 et un projet standard qui fait réference a ma dll portable:

image

et le tour est joué!

La question essentiel est dans quel cas cela est utile et quels type de code y mettre. Perso, je privilégierai les deux cas suivant:

  • tout ce qui est classe “utiles”: toutes les classes de traitement qui sont très souvent des classes statiques ou qui contiennent des méthodes d’extension aux types de base.
  • Les classes POCO: tant qu’a faire, autant qu’elles soient compatibles avec tout les frameworks (on ne sait jamais).
[C#] Design Pattern: Chaine de responsabilité

 

Cette semaine, on a eu avec un collègue à migrer du code…enfin, lui écrivait du code et moi je faisait des commentaires sur le code Sourire.

A un moment donnée, on (il) a été confronté a un problème classique de la POO: On avait un fichier de log alimenté par un traitement (Nant) et on devait en temps réel lire cette log (depuis un autre process C#); interpréter son contenu et remonter les informations. En gros: début de l’étape X, Fin de l’étape X, Etape X réussi, Etape X en Erreur, Etape de Chargement de donnée...

Pour résoudre cette problématique, on (il) a commencé a écrire le traitement qui lit le fichier et remonte ligne par ligne le fichier de log, puis fait passer cette ligne dans un ensemble de traitements chargé d’analyser si elle correspond à un ou plusieurs état à remonter (une voir plusieurs expressions régulières par type d’état ): une ligne peut signifier début de traitement + Erreur + Traitement de chargement des données,….

Et là, on s’est rendu compte que le code devenait trop complexe, on a donc chercher à le redesigner et le pattern qui nous est venu de suite en tête c’est le pattern Chaine de responsabilité (CoR).

Si on regarde la définition Wikipédia:

En génie logiciel, le patron de conception Chaîne de responsabilité permet à un nombre quelconque de classes d'essayer de répondre à une requête sans connaître les possibilités des autres classes sur cette requête. Cela permet de diminuer le couplage entre objets. Le seul lien commun entre ces objets étant cette requête qui passe d'un objet à l'autre jusqu'à ce que l'un des objets puisse répondre. Ce pattern permet aussi de séparer les différentes étapes d'un traitement.

image

 

On se rend compte que l’on est exactement dans la problématique visé par ce pattern:

le patron de conception Chaîne de responsabilité permet à un nombre quelconque de classes [Les classes qui vont tenter de voir si la ligne de log correspond a un état précis] d'essayer de répondre à une requête [Le traitement de ma ligne de log] sans connaître les possibilités [Mes classes ne sont en aucun cas liée et ne savent absolument pas comment les autres fonctionnent] des autres classes sur cette requête.

Dans notre cas, l’avantage de ce pattern par rapport à d’autres comme le Strategy ou Pipeline, c’est qu’on a la possibilité d’injecter autant de Handler qu’on le souhaite et que le traitement de la requette par ces differents Handlers est complètement découplé (ce qui n’est pas forcément le cas dans un pipeline).

On doit donc finir par avoir du code qui doit ressembler à ca:

le Handler (LogHandler) ainsi qu’un enum (flags) pour connaitre les types associés à la ligne de log :

 

   1: public abstract class LogHandler
   2: {
   3:  
   4:     protected string _regExp;
   5:     protected LogHandler _successor;
   6:  
   7:     public abstract TaskStatus HandleRequest(string log);
   8:  
   9:     public void SetSuccessor(LogHandler logHandler)
  10:     {
  11:         _successor = logHandler;
  12:     }
  13: }
  14:  
  15: [Flags]
  16: public enum TaskStatus
  17: {
  18:     None,
  19:     Started,
  20:     Finished,
  21:     Error,    
  22: }

Dans cette classe on a une regExp stockée dans une string. Un objet successor de type LogHandler et une méthode SetHandler (on pourrait très bien avoir une propriété avec juste un set).

les Handlers concrets qui override chacun la méthode HandleRequest en faisant bien sûr appel au successor (qui dans cet exemple est finalement un precedor), dans cet exemple ils font plus ou moins la même chose :

   1: public class TErrorHandler : LogHandler
   2:  {
   3:      public TErrorHandler()
   4:      {
   5:          _regExp = "Ma RegExp Error";
   6:      }
   7:  
   8:      public override TaskStatus HandleRequest(string log)
   9:      {
  10:          var status = TaskStatus.None;
  11:  
  12:          if(_successor!=null)
  13:              status = _successor.HandleRequest(log);
  14:  
  15:          Regex myRegex = new Regex(_regExp);
  16:          if(myRegex.IsMatch(log))
  17:          {
  18:              status |= TaskStatus.Error;
  19:          }
  20:          return status;
  21:      }
  22:  }
  23:  
  24:  public class TFinishedHandler : LogHandler
  25:  {
  26:      public TFinishedHandler()
  27:      {
  28:          _regExp = "Ma RegExp Finished";
  29:      }
  30:  
  31:      
  32:      public override TaskStatus HandleRequest(string log)
  33:      {
  34:          var status = TaskStatus.None;
  35:  
  36:          if(_successor!=null)
  37:              status = _successor.HandleRequest(log);
  38:  
  39:          Regex myRegex = new Regex(_regExp);
  40:          if(myRegex.IsMatch(log) && log.StartsWith("S") )
  41:          {
  42:              status |= TaskStatus.Finished;
  43:          }
  44:          return status;
  45:      }
  46:  }
  47:  
  48:  public class TStartedHandler : LogHandler
  49:  {
  50:      public TStartedHandler()
  51:      {
  52:          _regExp = "Ma RegExp Started";
  53:      }
  54:  
  55:      public override TaskStatus HandleRequest(string log)
  56:      {
  57:          var status = TaskStatus.None;
  58:  
  59:          if (_successor != null)
  60:              status = _successor.HandleRequest(log);
  61:  
  62:          Regex myRegex = new Regex(_regExp);
  63:          if (myRegex.IsMatch(log) && log.StartsWith("S"))
  64:          {
  65:              status |= TaskStatus.Started;
  66:          }
  67:          return status;
  68:      }
  69:  }

et la classe Client :

   1: public class Client
   2:   {
   3:  
   4:       private LogHandler _chainOfResponsibility;
   5:       public void LoadHandlers()
   6:       {
   7:           var startedHandler = new TStartedHandler();
   8:           var errorHandler = new TErrorHandler();
   9:           var finishedHandler = new TFinishedHandler();
  10:  
  11:           startedHandler.SetSuccessor(errorHandler);
  12:           errorHandler.SetSuccessor(finishedHandler);
  13:  
  14:           _chainOfResponsibility = startedHandler;
  15:  
  16:       }
  17:  
  18:       public void Request(string log)
  19:       {
  20:           var status = _chainOfResponsibility.HandleRequest(log);
  21:           if (status != TaskStatus.None)
  22:           {
  23:               SendMessageToSystem(status);
  24:           }
  25:       }
  26:  
  27:  
  28:       private void SendMessageToSystem(TaskStatus status)
  29:       {
  30:           throw new NotImplementedException();
  31:       }
  32:  
  33:   }

On a :

  • une méthode loadHandlers chargée de construire notre chaine de traitement. On construit et associe nos différents handlers avec comme point d’entrée l’objet _chainOfResponsibility.
  • une méthode Request: qui lance notre chaine  de traitements, récupère les status et envoi un message si on doit le faire.

Alors, bien sûr, le traitement présenté ici est simplifiée le but étant bien évidement de présenter le pattern CoR.

On obtient du code bien découplé, simple a lire (chaque handler contient du code spécifique à ce qu’il tente d’intercepter) facile à modifier…bref un code SOLID!

 

L’exemple est dispo ici

[VS 2012-Fakes Framework] Bienvenue chez les Shims!

 

Lorsque l’on fait des Tests unitaires, l’une des principales difficultés que l’on rencontre, c’est l’isolation de la méthode que l’on souhaite tester : très souvent ca passe par des mocks, des stubs ou des fakes.

Là où les choses se compliquent, c’est lorsque vous utiliser des API ou des Framework externes dont vous ne maitriser pas le code et là, bonjour la galère pour mocker votre système…et dans bien des cas, ça devient tellement complexe (et/ou couteux) que l’on préfère ne pas tester ces portions de code.

On va voir dans ce post comment le « Fakes Framework » inclus dans VS 2012 permet de manière élégante et très simple de solutionner ce problème.

Prenons cet exemple :

Nous avons un Framework avec une classe ParamManager (sealed…comme ca on ne peut pas générer de stub via RhinoMock ;) ) et qui possède une méthode statique GetValue.

 
public sealed class ParamManager
    {
        public static int GetValue(string paramName)
        {
            if (string.Equals(paramName, "A",
 StringComparison.InvariantCultureIgnoreCase))
            {
                return 5;
            }
            else
            {
                return 2;
            }
        }
    }

Puis nous avons le code que nous développons : la classe Foo qui utilise la classe ParamManager via la classe GetFoo:

    public class Foo
    {
        public int GetFoo(int initalValue)
        {
            var paramName = "a";
            int paramValue = ParamManager.GetValue(paramName);
 
            return paramValue * initalValue;
        }
    }

Avant le « Fakes framework », on aurait fait de l’IoC afin de casser le couplage entre les classes Foo et ParamManager et permettre de facilement isoler et tester la classe Foo :

On casse la dépendance en utilisant une interface IParamManager qui est utilisée par notre classe FooClean.

    public class FooClean
    {
        private IParamManager _paramManager;
 
        public FooClean(IParamManager paramManager)
        {
            _paramManager = paramManager;
        }
 
 
        public int GetFoo(int initalValue)
        {
            var paramName = "a";
            int paramValue = _paramManager.GetValue(paramName);
 
            return paramValue * initalValue;
        }
    }
 
    public interface IParamManager
    {
        int GetValue(string paramName);
    }

On ajoute une nouvelle classe MyParamManager qui implémente l’interface IParamManager et qui utilise la classe du framework ParamManager.

public class MyParamManager : IParamManager
    {
 
        public int GetValue(string paramName)
        {
            return ParamManager.GetValue(paramName);
        }
    }

Lorsque l’on est dans une configuration « métier » (ie on souhaite utiliser la classe FooClean à l’identique de la classe Foo); on utilisera donc la classe FooClean avec l’objet MyParamManager en paramètre du constructeur (on fait de l’injection par constructeur).

Du coup, tester notre nouveau code devient simple en utilisant un framework de Mock comme RhinoMock par exemple:

       [TestMethod]
        public void TestFooClean()
        {
            var p = MockRepository.
                    GenerateMock<IParamManager>(null);
            p.Stub(x => x.GetValue("a")).Return(4);
            
            FooClean f = new FooClean(p);
            var value = f.GetFoo(2);
 
            Assert.AreEqual(8, value);
        }

Ça marche nickel et je dirais même que c’est une bonne solution car elle permet aussi de découpler notre code…sauf que dans ce cas simple, ça marche comme sur des roulettes mais dans des cas compliqués ou les objets de notre framework interagissent entre eux : ça devient quasi impossible d’avoir un code proprement mockable donc testable unitairment.

VS 2012 permet de résoudre simplement et de manière élégante cette problématique. Reprenons notre exemple et voyons comment tester notre classe Foo sans avoir à inverser les dépendances.

On va utiliser les Shims :les shims permettent d’intercepter et de rediriger au runtime des appels de méthodes. Ainsi, lorsque notre objet de type Foo va faire son appel à la methode GetValue, on va pouvoir rediriger cet appel vers une autre méthode que l’on aura défini pour les besoin de notre test. Du coup, plus besoin d’IoC (de modification du code) ou de mocks, on peut tester la classe Foo sans avoir à la modifier!

Comment on fait ? Premièrement, on doit ajouter une dll « Fake » pour la dll « Framework » : c’est dans cette nouvelle dll que vont être générer automatiquement les shims et à partir desquelles on va pouvoir créer nos méthodes de substitution.

Pour ca, click droit sur la réference et “Add Fakes Assembly”: 

image

Ensuite, on va utiliser l’objet généré pour définir notre méthode de substitution, une simple lambda qui renvoi tjr –4:

 

ShimParamManager.GetValueString = s => -4;

Enfin, on va pouvoir écrire notre test sur la méthode GetFoo de la classe Foo :

[TestMethod]
        public void TestFoo()
        {
            using (ShimsContext.Create())
            {
                ShimParamManager.GetValueString = s => -4;
 
                Foo f = new Foo();
                var value = f.GetFoo(2);
                Assert.AreEqual(-8, value);
            }
        }

Ca marche et sans avoir toucher une ligne de notre code initiale Sourire

Vous devez ajouter un block using avec un “ShimContext” tout simplement pour s’assurer qu’a la fin du block, les shims définis soient tous disposés. Comme ca, vous ne risquer pas d’avoir de télescopage entre deux TU.

Il aussi est important de souligner que le « Fake Framework » sera (malheureusement) disponible avec la version Ultimate de VS 2012 et que les classes de base du framework .NET « mscorlib » et « system» ne peuvent avoir de Shims.

[Event] Windows Azure dev Camp le 20 juin!

Si vous avez un peu de temps et que vous souhaitez vous mettre à Azure, MS organise un dev Camp le 20 juin à Issy les Molineaux:

image028

Au programme:

· Présentations et démos exclusives des nouveautés de la plateforme

· Échanges avec des membres de l'équipe de développement Windows Azure spécialement venus de Seattle

· Des contests avec des Nokia Lumia 800 et plein d'autres prix à gagner

· Sans oublier des pizzas, des goodies et des offres sympas de nos partenaires !



Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01