mathieu szablowski

Titulaire d'un master en informatique de l'École Supérieure d'Informatique de Paris, Mathieu oeuvre depuis plus de 8 ans dans la réalisation de solutions logicielles, notamment à l'aide de la plateforme Microsoft .NET. Au cours des trois dernières années, il a suivi l'émergence de la plateforme Team System et contribué à la mise en place de cette solution et des pratiques logicielles Agiles dans de nombreuses équipes.
voir mon profil complet »

Articles de mathieu :


    Je mocke, tu mockes, il mocke… nous loupons un refactoring

    Avant de mocker un composant, assurez vous que les difficultés que vous rencontrez à le tester ne proviennent pas du composant lui même.

    PS : Je sais c’est court mais je crois que c’est pertinent et que le message passera mieux. D’autant que je m’en fait un pense bête à lire 10x ou 15x par jour tellement c’est évident et qu’on arrive à passer à côté.

    Test d’intégrataire ou test d’unigration

    Ces dernières semaines durant mon développement ou autour d’un autre binôme à Pyxis, j’ai été confronté à cette discussion qui trainait et qui au final ralentissait le développement :

    Membre de l’équipe 1 : A ton avis, c’est un test d’intégration ou un test unitaire?

    Membre de l’équipe 2 : ouf, y’a un fichier XML à utiliser, je vois pas comment s’en passer sans perdre le sens du test, çà doit forcement être un test d’intégration.

    Membre de l’équipe 1 : Oui mais, il y a pleins de traitement différents que j’aimerais tester unitairement alors faire un test d’intégration avec le fichier…

    Membre de l’équipe 2 : bon bah on va faire deux tests alors. Mais on fait quoi en premier?

    Membre de l’équipe 1 : Bah c’est évident, on commence par l’unitaire.

    Membre de l’équipe 2 : Et on fait comment pour le fichier?

     

    Constat

    A partir de ce point, on tourne en rond. On cherche à tester unitairement pour se rendre compte que l’on n’arrive pas à isoler ce maudit fichier.

    Pattern

    De ce que j’ai pu observé dans les différentes situations auxquelles j’ai été confrontées, le problème était le même. La question ne venait pas de la façon d’aborder les tests du composant mais bien le composant en lui même. Celui-ci dépendait d’une ressource (fichier XML, base de données, Service distant) lui fournissant des services de données. Ce même composant proposait un certain nombres de routines de traitement de ces mêmes données.

    Logique + données, pourquoi ne pas séparer?

    Au final, la résolution passait par une séparation de ces deux aspects du comportement. On extrait la partie accès aux données et la partie traitement. Rien de novateur, là dedans, ce qui l’est davantage pour moi (et je pense que vous en conviendrez), c’est que les tests ont facilité de détecter ce pattern et par expérience désormais si j’entend un développeur se posait la question : Test d’intégration ou test unitaire? je lui suggérerais en tout premier lieu de revoir le code ciblé par le test( ou l’idée qu’il s’en faisait en TDD).

     

    Rhino Mock / MSTest : Isolation

     

    Dans ce post, j’aimerais vous présenter diverses méthodes permettant d’effectuer des tests de comportements sur vos composants. On ne teste pas le contexte, les données retournées mais bien le comportement de la routine avec l’appelant et les dépendances.

    Contexte

    On souhaite tester une méthode d’un dépôt(notion de repository en DDD). La routine en question est un service permettant d’envoyer des entités (Demande) à un service Web pour centraliser ces demandes. Les différentes actions effectuées sont les suivantes :

    L’appelant appelle la méthode EnvoyerTout prenant en paramètre une liste de Demande.

    Le dépôt reçoit la liste et vérifie les informations de synchronisation dans une base de données locale.

    Le dépôt envoie la liste des demandes et les informations de synchronisation au service.

    Le service répond et fournit des informations permettant d’enregistrer en local que les demandes ont déjà été envoyé au serveur.

    Afin de limiter le trafic réseau, on souhaite vérifier que les demandes réellement envoyées au serveur n’avait jamais été envoyées. Cette information est disponible dans la base de données de locale.

    On souhaite isoler le comportement de cette routine car nous détectons rapidement les différentes dépendances :

    Un service Web qui doit répondre aux différentes requêtes du proxy.

    Une base de données contenant des informations de synchronisation.

    Une utilisation d’une dépôt permettant de récupérer les informations de l’utilisateur.

    Explication du test

    Voici donc le test en question :

     1: [TestMethod]
     2:         public void EnvoyerToutNAjouteQueLesDemandesJamaisSynchronisees()
     3:         {
     4:             utilisateurDepot = mockRepository.Stub<IUtilisateurDepot>();
     5:             demandeDeControleService = mockRepository.StrictMock<DemandeDeControleService>();
     6:             demandeDeControleServeurDepot = mockRepository.Stub<DemandeDeControleServeurDepot>(demandeDeControleService, utilisateurDepot);
     7:             Expect.Call(demandeDeControleServeurDepot.GetReplicaId()).Return(Guid.NewGuid());
     8:             demandeDeControleServeurDepot.MettreAJourTousLesWatermark(null, 0);
     9:             LastCall.IgnoreArguments();
     10: 
     11:             Expect.Call(demandeDeControleService.EnvoyerTout(null)).IgnoreArguments().Return(0).Repeat.Once();
     12:             mockRepository.ReplayAll();
     13: 
     14:             demandeDeControleServeurDepot.EnvoyerTout(CreerUneListeDeDemandes(5, 2));
     15: 
     16:             ServiceDomain.DemandeDeControle[] demandeDeControleEnvoyees =
     17:                 (ServiceDomain.DemandeDeControle[])demandeDeControleService.GetArgumentsForCallsMadeOn(x => x.EnvoyerTout(null)).First().First();
     18:             Assert.AreEqual(2, demandeDeControleEnvoyees.Length);
     19:         }

    Pour décrire ce test commençons par le commencement d’un test à savoir son assertion :

    Ligne 18 :  Assert.AreEqual(2, demandeDeControleEnvoyees.Length); On vérifie ici que le nombre de demandes envoyés au serveur est bien égale à 2.

    On pourrait donc traduire cette assertion de la sorte : Si l’application fournit une liste de 5 demandes au dépôt mais que seuls 2 demandes de cette liste doivent être envoyées au serveur, vérifie que le dépôt n’a envoyé que ces 2 éléments au service.

    Pourquoi?

    Ligne 14 : demandeDeControleServeurDepot.EnvoyerTout(CreerUneListeDeDemandes(5, 2)); C’est la routine que nous souhaitons tester. Dans le test, le paramètre (la liste de demandes suceptibles d’être envoyées) est fourni par une méthode du test CreerUneListeDeDemandes(5, 2) prenant en paramètre le nombre total de demande à créer et le nombre de demandes à synchroniser (et qui doivent donc réellement être envoyées au serveur).

    Et la rapport avec l’assertion?

    Ligne 16 et 17 : On récupère le premier paramètre du premier appel (il n’y en a qu’un) de l’exécution de la méthode EnvoyerTout d’un mock (demandeDeControleService) .C’est le cœur même du test et l’objet de l’assertion. Ces paramètres proviennet directement du mock, le service n’est jamais instancié.

    Et comment c’est possible?

    De la ligne 4 à la ligne 9 : on prépare l’exécution du test en isolant, à l’aide de diverses techniques et fonctionnalités de RhinoMock, les dépendances détectées.

    Ligne 4 : on crée un stub du dépot utilisateur, aucun comportement ou données ne nous sont nécessaires. Nous avons juste besoin d’une instance de ce dépot pour l’instanciation ligne 6. Le fait de le “stuber” permet de ne pas exécuter le code de ce dépôt.

    Ligne 5 : On crée un mock strict. Toutes les fonctionnalités du service seront recrées et tous les appels vers le service seront redirigés vers ce mock.

    Ligne 6 à 12 : Création du mock partiel du composant testé. Toutes les routines réclamant un contexte (ligne 7 et 8, la récupération des informations de synchronisation nécessite une base de données locale) sont redirigés vers le mock. On peut configurer le résultat de l’exécution de la méthode du mock (ligne6 : demandeDeControleServeurDepot.GetReplicaId()).Return(Guid.NewGuid()) ) ou l’on peut déclarer d’ignorer l’appel et les paramètres (ligne 7).

    Sur ce mock partiel, on appelle la méthode testée (ligne 11).

    Tous les comportement d’isolation ne seront disponibles qu’après la ligne 12. Celle-ci permet d’informer RhinoMock des différentes instructions d’isolation.

    Conclusion

    Pas de base de données à construire et de données à générer. Pas de service sur un serveur de test. Mais le comportement attendu est vérifié et le sera même en cas de changement de source de données, de modification du contrat de service…

    Cool non?

     

     

    Mise sur étagère : ou comment revoir un flux de développement TDD avec TFS

    La mise sur étagère dans Team Foundation Version Control est l’une des fonctionnalités qui m’a le plus rapidement séduit.

    Classiquement, on s’en sert pour enregistrer une modification du source non achevée ( not done) mais que l’on souhaite conserver sur un serveur sauvegardé pour le récupérer en cas d’incident sur notre propre poste. Martin avait écrit un excellent billet à ce sujet.

    On peut également l’utiliser pour communiquer nos modifications sur notre espace de travail avec d’autres développeurs, pour fusionner le travail, lors d’un binômage etc…

    Récemment, j’ai surtout pris l’habitude de mettre sur étagère dans mon flux de développement en TDD (ou plutôt en Test First Programming, certains connaissent mon attachement à cette différenciation).

     

    Voici donc ce nouveau flux :

    Définir le test

    1. Définir le test, en particulier son nom
    2. Ecrire les assertions (ce que je vérifie)
    3. Définir mes besoins (contexte, instanciation des composants testés)
    4. Appel de la routine à tester

     

    Obtenir le résultat du test (Red bar)

    A ce stade, le projet ne compile pas en général, puisque rien n’est implémenté. L’objectif suivant est de faire compiler ce projet.

    1. Je déclare les différentes variables
    2. j’implémente au minimum l’objet du test (création du type, de la routine)

    Ici, j’en arrive au point ou je compile et il ne me reste qu’à implémenter la fonctionnalité avec l’assurance de tester automatiquement celle-ci. C’est pour moi le moment idéal d’effectuer une mise sur étagère des modifications de mon espace de travail. Celui-ci me permet d’être plus à l’aise dans l’implémentation, en cas de problème, je peux revenir en arrière par l’ensemble d’actions :

    1. Undo : annulation des modifications en attentes
    2. Get : Récupération de la dernière version (facultatif)
    3. Unshelve : Récupération du cadre de développement de la fonctionnalité à savoir mon test

     

    Essayez ce flux, c’est l’adopter.

    La fonctionnalité : Lier à un élément de travail

    Etant actuellement impliqué dans un projet agile autour de Team Foundation Server (un peu plus à ce sujet très prochainement), j’ai décidé de faire partager mon expérience du produit lors de chacune des Daily Meetings. C’est donc l’occasion pour moi de revenir sur mes basiques et surtout de faire un point sur ce qu’on attend des fonctionnalités de Team Foundation Server et ce qu’elles apportent réellement à l’équipe.

     

    Lier à un élément de travail

     

    Description : Lors de l’archivage d’une modification du projet, le développeur a l’opportunité de lier cette modification à un ou plusieurs éléments de travail. Un lien est alors créé entre son jeu de modifications (changeset) et l’élément de travail.

     

    image

    1 : Lors de l’archivage, le 2° bouton dans le menu de gauche permet de lier la modification à un élément de travail

     

    image

    2 : une requête permet de sélectionner l’élément de travail (par défaut les éléments de travail qui me sont assignés : “My Work Items”)

     

    image image

    3 : Le développeur peut agir directement sur l’élément de travail en sélectionnant l’action (associer l’élément de travail ou le résoudre)

     

    image image

     

    Une fois l’archivage effectué, le lien est présent dans l’historique du contrôleur de code source à l’aide dans le détail de l’archivage et depuis la base de l’élément de travail à l’aide d’un lien vers le contrôleur de code souce.

     

    Les apports

     

    En deux clics de la part du développeur on obtient une traçabilité “technico fonctionnelle”. J’entends par là que chacune des actions des développeurs, des testeurs et des architectes sont réliées à la demande ou au besoin initial. N’oublions pas que l’ensemble des ses informations vont persistées dans la base (SQL Server) pour des années et permettront de naviguer dans l’historique du projet et ainsi de :

    • Définir quelle était la cause d’une modification du contrôleur de code source
    • Déterminer l’impact de l’implémentation d’une fonctionnalité ou d’un correctif

     

    Mise en place et Risques

     

    Pas de mise en place particulière, il suffit d’avoir des éléments de travail à lier à vos modifications. Il s’agit donc de préparer les développements et les différentes tâches de l’équipe. Au niveau des risques, il est important de lier chaque modification du code source à un et un seul élément de travail. Rappelons que lors d’un archivage, tous les fichiers modifiés dans l’espace de travail sont sélectionnées mais qu’il est possible de construire son jeu de modifications en sélectionnant les seuls fichiers qui ont permis d’implémenter la fonctionnalité ou de résoudre un bug.

    Contourner l’intégration continue

    De plus en d’équipes pratiquent l’intégration continue. Team Build et Team Foundation Server sont particulièrement bien dotés pour cela :

    • Démarrage des builds basé sur les évènements du contrôleur de source
    • la configuration est facile et permet d’empiler des compilations et de définir le nombre de builds à conserver afin de limiter l’espace disque utilisé par exemple

    Cependant, il peut être utile de contourner le lancement de la compilation lors d’un archivage ( édtion d’un script de build, création d’une branche…).

    Lors de l’archivage de votre changeset, placez en tête de votre commentaire le texte suivant :

    ***NO_CI***

    Cette commande indiquera au moteur de build que vous ne souhaitez pas déclencher l’intégration continue.

    Surveiller un serveur TFS

    images

     

    Basées sur mon expérience et les différentes installations que j’ai pu rencontré, voici mes recommandations concernant la supervision d’un serveur TFS.  Celles ci ne sont pas exhaustives et doivent être majorées suivant votre topologie et les ressources matérielles de votre serveur. J’attends vos éventuels retours afin de préciser ce billet.

     

    Quelque soit l’outil de supervision ou les procédures que vous voici une liste non-exhaustive des points que vous devez surveiller sur votre serveur TFS.

     

    Configuration matérielle

     

    Consommation CPU : dépend du nombre d’utilisateurs actuellement connectés. Une forte consommation CPU peut survenir lors de la génération du Warehouse et/ou de la consultation des rapports et de Sharepoint. Sur une heure, une consommation inférieure à 30% du CPU devrait représenter un comportement normal.

    Consommation mémoire : Une forte consommation mémoire peut être observé sur une instance unique (AT + DT), cela est causé par SQL Server 2005 qui prend ses aises.

    Espace disque : Dépend fortement de la volumétrie (nombres de projets d’équipe). Une partition système doit disposer d’au moins 4Go de libre afin d’accueillir les MSI de mise à jour, la partition de données ne devrait pas excéder 50% d’espace occupé.

    Connectivité : les adresses IP de la machine sont elles celles attribuées lors de l’installation. Le nom de la machine est il celui d’origine.

     

     

    IIS

     

    Les sites Web suivants sont ils démarrés?

     

    Default Web Site

    Sharepoint Central Administration v3

    Team Foundation Server

    Team System Web Access

     

    Les pools d’applications suivants sont ils démarrés?

     

    Microsoft Team Foundation Server Application Pool

    ReportServer

    TFS WSS

    DefaultAppPool

    Sharepoint Central Administation V3

    TswaPool

     

    Vérifier les en-têtes d’hôte et les éventuels certificats .

     

    Services Windows

     

    Les services suivants sont ils démarrés?

    TFSServerScheduler

    SharePoint Timer Service

     

    Journaux d’ événements

     

    Surveiller toutes les entrées concernant Team Foundation Server bien sûr (Erreur TFXXXXXX) mais également celles liés à SQL Server et surtout à son agent (Sauvegardes), à Sharepoint et à Reporting Services. Vous pouvez également considérer tous les erreurs provoqués lors de l’exécution d’une application par les différentes comptes de services de TFS.

     

    Les alertes concernant Team Foundation Version Control et Team Foundation WorkItem Tracking sont considérées comme critiques. Les alertes concernant  TfsWarehouse et Reporting Services sont sérieuses.

     

    SQL Server

     

    Les services suivants sont ils démarrés?

     

    Database Services

    Analysis Services

    Reporting Services

    SQL Server Browser

    SQL Server Agent

     

    Les dernières exécutions des sauvegardes se sont elles bien déroulés?

    Vérifiez la présence des fichiers et l’historique des jobs SQL Server.

    KB947455 – Actions “Delete” répétées durant les fusions

     

    Petit rappel : Une fusion dans Team Foundation Version Control est constituée d’une liste de “jeux de modifications” (ChangeSets en anglais) que l’on souhaite reporter d’une branche à l’autre. Les jeux de modifications comporte des actions (ajout, renommage, édition…) appliquées à des Items(les fichiers et les dossiers). La fusion consiste donc à répéter les différentes actions sur les items d’un jeu de modifications sur les items communs entre les branches.

     

    Problème : Les actions de suppression des fichiers ne sont pas répétés durant les fusions dans TFVC 2005 et TFVC 2008. Les fichiers qui ont été supprimés dans la branche de destination seront donc toujours présents malgré le report de l’ensemble des modifications dans la branche Cible. Le problème est connu et une KB est disponible ici : http://support.microsoft.com/default.aspx/kb/947455/en-us

     

    Résolution : Microsoft vient de publier un correctif visant à permettre de reporter les opérations de suppression à l’aide d’une opération de fusion. Ce correctif est disponible ici : http://code.msdn.microsoft.com/KB947455/Release/ProjectReleases.aspx?ReleaseId=1127 .

    Il permet donc de voir apparaître des actions de suppression lors de la fusion entre deux branches.

    Dans l’exemple ci-dessous, il s’agit du fichier web.config qui devra être supprimé après la fusion.

    image

     

    Nous avons bien l’effet attendu en vérifiant après la fusion les modifications en attentes sur l’espace de travail :

     

    image

     

    A noter toutefois que ce correctif ne permet pas de reporter des suppressions entre deux dossiers à l’aide de l’option /Baseless disponible à l’aide de l’outil en ligne de commande tf.exe, comme en témoigne le résultat des modifications en attentes ci-dessous.

     

    Après exécution de la commande :

    image

    image

     

    On constate donc que le fichier qui a été supprimé dans la branche source a donc été ignoré lors de la fusion.

    Erreur 32000 lors de la migration de TFS 2008

    Voici une entrée dans laquelle je vais présenter un problème que vous pourriez rencontrer lors d’une migration de votre serveur Team Foundation.

     

     

    Bien que dans la majorité des migrations que nous effectuons, la procédure se résume à la simple exécution du programme d’installation, certaines petites manipulations ou configurations peuvent vous posait problèmes durant cette opération. Il semblerait que ce soit le cas pour la migration que j’ai opéré aujourd’***. Il s’agit d’une instance installée il y a de cela deux ans, qui n’a jamais posé de problème particulier hormis peut être avec Analysis Services. La remise en état du Warehouse se résumait à une reconstruction de l’entrepôt de données.

     

    Voici donc l’erreur rencontrée durant la phase d’installation / migration:

     

    Erreur 32000 : The Commandline ‘”C:Program FilesMicrosoft Visual Studio 2008 Team Foundation ServerToolsTfsDb.exe” upgrade /server:”SERVER” /property:”TFS_SERVICE_ACCOUNT=SERVERTFSSERVICE;TFS_REPORTING_ACCOUNT=SERVERTFSREPORTS;LCID=1033;VSTF_AS_INSTANCE=SERVER;VSTF_AS_DATABASE=TFSWarehouse” /showui:196682′ returned non-zero value: 100.

     

    Cette erreur apparaît lors de la mise à jour de l’entrepôt de données, tiens, tiens…

     

    La consultation des logs de l’installation présents dans les fichiers temporaires de l’utilisateur procédant à la migration nous révèle un premier indice :

    Erreurs dans le gestionnaire de métadonnées. Une erreur s’est produite lors de l’instanciation d’un objet de métadonnées du fichier, « \?E:Program FilesMicrosoft SQL ServerMSSQL.2OLAPDataTFSWarehouse.0.dbToday.1452.dim.xml ».

     

    En allant consulter le fichier indiqué dans le journal d’installation, j’ai pu constater qu’il s’agissait des informations de construction de la dimension Today du cube de Team Foundation Server. Dans ce fichier, qui semble être le fruit d’une sérialisation XML, l’erreur se comprend enfin : le fichier n’est pas valide, plus encore, il ne possède pas de balise de fin et n’est donc pas bien formé.

    Après avoir pris conseil auprès de certains collègues plus au fait que moi dans les affaires de cubes et d’entrepôts, je prends mon courage à deux mains et renomme la dizaine de fichiers *.dim.xml qui semblent poser problèmes pour constater :

    • Que l’installation s’achève sans autre avertissemnet
    • Que les fichiers *.dim.xml ont été regénérés

    L’architecture de Team Foundation est venue à notre rescousse car l’entrepôt de données et le cube peuvent être regénérés uniquement à l’aide des données présentes dans les différentes bases relationnelles (les données opérationnelles de TFS). Le fichier WareHouseSchema.xml, présent dans le répertoire d’installation de TFS, contient l’intégralité des définitions nécessaires à sa reconstruction et bien entendu , nous n’aurions pas pu supprimer la définition des dimensions dans une définition standard d’un entrepôt.

     

    En espérant que vous n’ayez pas à vous servir de ce post…