BT

Diffuser les Connaissances et l'Innovation dans le Développement Logiciel d'Entreprise

Contribuez

Sujets

Sélectionner votre région

Accueil InfoQ Articles Stratégie de Test pour les Interfaces d'Entreprise

Stratégie de Test pour les Interfaces d'Entreprise

L'interfaçage est un sujet qui ne peut être ignoré pour les applications d'entreprise : non seulement l'interfaçage avec des systèmes tiers est une source d'erreurs, et, de plus, ces applications sont difficilement testables. Cet article présente une stratégie de test des interfaces, applicables de manière généralisée, qui améliore la couverture, la vitesse d'exécution, la fiabilité et la reproductibilité des tests, et pourrait, de fait, servir de référence pour l'implémentation et le test d'applications fortement intégrées.

Background

Le système que nous utiliserons comme exemple dans cet article est une application web Java EE typique, dévelopée avec Java 6 et Spring, et construite avec Maven. Ce système s'intègre avec deux autres systèmes tiers via XML sur HTTP.

Cette application est fournie par une équipe distribuée : les représentants du métier sont à Melbourne, alors que l'équipe qui délivre se trouve à Sidney et Chengdu. L'un des auteurs, Jeff Xiong, est le responsable technique de l'équipe de Chengdu, qui prend une grande partie de l'effort de livraison.

La problématique

L'application doit s'interfacer avec deux systèmes tiers, et donc certains de nos cas de tests (écrits en Junit) doivent s'interfacer avec ceux-ci, ce qui rend le processus de construction1 avec Maven instable.

La fiabilité des services tiers n'est pas garantie. L'un de nos services dépendant est également en cours de développement, et souvent coupé, ce qui provoque l'échec de nos tests d'intégration (et du processus de construction dans son intégralité). Notre équipe de livraison suit scrupuleusement les pratiques de livraison continue, et ne lancera pas de check-in du code lorsque la construction est en échec. Dans ce cas-là, l'instabilité du service dépendant devient un point de blocage pour l'équipe.

Pire, les services déployés en environnement de développement ne sont pas aussi optimisés qu'en production, ce qui cause de graves problèmes de performance. De tels désavantages ralentissent fortement notre processus de construction et cause parfois des pannes aléatoires.

Comme le manque de fiabilité et la performance limitée du service externe rendent le processus de construction à la fois fragile et très lent, le team de construction rencontre fréquemment des difficultés pour construire. De plus, cela affecte l'efficacité du processus d'intégration continue. En tant que responsable technique, j'espère résoudre ce problème pour rendre la construction soit rapide et fiable.

Comment tester les interfaces

Lorsque les applications construites avec le framework Spring doivent s'interfacer avec des systèmes tiers, elles le font généralement via une interface Java. Par exemple, un service créant des clients pour une marque pourrait ressembler à celà :

public interface IdentityService {

       Customer create(Brand brand, Customer customer);
}

Spring instancie une classe implémentant IdentityService et conserve cette instance dans le contexte d'application, ainsi le code client qui nécessite ce service peut la récupérer via l'injection de dépendences et appeler sa méthode "create". Nous pouvons injecter une instance mockée d'IdentityService dans le code client lors de l'écriture du test ; de cette manière, nous découplons le code de test du service externe. C'est l'un des bénéfices de l'injection de dépendences.

Comme nous n'avons pas à nous préoccuper de tester le code client, notre attenetion peut se porter sur le test des interfaces de notre système.

Pour s'intégrer avec un service HTTP dans un langage orienté-objet, les interfaces sont généralement conçues sur cinq composants majeurs : façade, constructeur de requête, routeur de requête, extrémité réseau et analyseur de Réponse. Le diagramme suivant montre leurs interactions :

Comme vous pouvez l'observer sur le diagramme, l'extrémité réseau est l'unique composant qui traite avec le monde externe via les requêtes HTTP. Il envoie une certaine requête à une certaine adresse web dans un protocole prédéfini et retourne la réponse. L'extrémité réseau est généralement défini comme suit pour les services HTTP :

public interface EndPoint { 
            Response get(String url);
            Response post(String url, String requestBody);
            Response put(String url, String requestBody);
}

La classe de réponse contient 2 éléments d'information : le code statut HTTP et le corps de la réponse.

public class Response {
           private final int statusCode;
           private final String responseBody;
}

Vous avez sans doute remarqué que la classe EndPoint est responsable de l'envoi d'une requête donnée à une adresse donnée et du retour de la réponse au service externe. Elle ne se préoccupe pas de ce qu'est l'adresse (c'est le boulot du routeur de requête) ni du contenu de la requête ni de la réponse (le constructeur de requête et l'analyseur de réponse les prennent respectivement en charge). Cela rend les tests d'EndPoint totalement indépendants des services tiers existants.

Tester les Extrémités Réseau

Ce qui préoccupe réellement la classe EndPoint, c'est de savoir si c'est la manière correcte d'envoyer des requêtes et de récupérer des réponses - la "manière correcte" peut comprendre l'authentification et l'autorisation, les en-têtes HTTP nécessaires, etc. Afin de tester cette classe, nous n'avons pas besoin d'envoyer des requêtes à l'adresse du serveur distant et d'obéir au protocole de requête/réponse réel. Au lieu de celà, nous pouvons créer notre propre serveur HTTP et le tester avec une requête/réponse très simple.

Moco est un outil de test conçu à cet effet. Suivant l'introduction de l'auteur, il s'agit "d'un framework de bouchon facile à mettre en place et se focalisant surtout sur le test et l'intégration". La création d'un serveur HTTP nécessite uniquement deux lignes de code - le serveur créé sera disponible sur le port 12306 et répondra avec la chaîne de caractères "foo" à toute requête :

MocoHttpServer server = httpserver(12306);
server.response("foo");

Nous pouvons alors accéder à ce serveur HTTP comme n'importe quel autre serveur réel avec Apache Commons HTTP Client. Un seul point doit retenir votre attention : le code qui interagit avec le serveur doit être positionné dans le bloc "exécuté" de sorte que le serveur puisse être éteint.

running(server, new Runnable() {
    @Override
    public void run() throws IOException {
        Content content = Request.Get("http://localhost:12306").execute().returnContent();
       assertThat(content.asString(), is("foo"));
    }
}

Bien sûr, en tant qu'outil de test, Moco supporte également plusieurs options de configuration : si vous êtes intéressés, lisez le manuel en-ligne. Pour le moment, jetons un oeil sur la manière d'utiliser Moco pour tester un composant d'extrémité de réseau dans une interface. Comme illustration, nous allons intégrer OpenPTK, qui fournit un pont entre les solutions d'identité et des points d'accès ou de interfaces utilisateurs spécialisés. OpenPTK utilise un protocole de communication XML personnalisé et impose à ses clients l'envoi de requêtes à l'adresse /openptk-server/login avec le nom de l'application et le mot de passe avant chaque requête pour s'assurer que l'application est autorisée. De fait, nous préparons un serveur Moco de test comme ci-après :

server = httpserver(12306);
server.post(and(
        by(uri("/openptk-server/login")),
        by("clientid=test_app&clientcred=fake_password"))).response(status(200));

Puis, nous configurons l'extrémité de réseau pour accéder à notre serveur Moco situé à localhost:1236 avec le nom d'utilisateur et le mot de passe :

configuration = new IdentityServiceConfiguration();
configuration.setHost("http://localhost:12306");
configuration.setClientId("test_app");
configuration.setClientCredential("fake_password");
xmlEndPoint = new XmlEndPoint(configuration);

Finalement, notre banc d'essai est prêt. Il est temps de vérifier que XmlEndPoint est capable d'accéder une URL spécifiée avec une requête HTTP GET et de récupérer la réponse :

@Test
public void shouldBeAbleToCarryGetRequest() throws Exception {
    final String expectedResponse = "<message>SUCCESS</message>";
    server.get(by(uri("/get_path"))).response(expectedResponse);
    running(server, new Runnable() {
        @Override
        public void run() {
            XmlEndPointResponse response = xmlEndPoint.get("http://localhost:12306/get_path");
            assertThat(response.getStatusCode(), equalTo(STATUS_SUCCESS));
            assertThat(response.getResponseBody(), equalTo(expectedResponse));
        }
    });
}

Un autre cas de test est nécessaire pour décrire le scénario "échec de l'authentification", de sorte que nos tests couvriront tous les cas pour la méthode get de la class XmlEndPoint :

@Test(expected = IdentityServiceSystemException.class)
public void shouldRaiseExceptionIfLoginFails() throws Exception {
    configuration.setClientCredential("wrong_password");
    running(server, new Runnable() {
        @Override
        public void run() {
            xmlEndPoint.get("http://localhost:12306/get_path");
        }
    });
}

En suivant cette approche, il est aisé de créer aussi des cas de test pour les méthodes POST et PUT. Avec Moco, nous complétons tout les tests pour les extrémités réseaux. Bien que ces tests impliquent de vraies requêtes HTTP, elles ne font qu'interagir avec un serveur localhost créé par Moco et ne réalisent que des requêtes HTTP GET/POST/PUT basiques. De fait, les cas de tests sont rapides et fiables tout le temps.

Test d'autres composants

Comme nous avons testé les extrémités, le test des autres composants ne nécessite pas l'envoi d'aucune requête HTTP. Dans un monde idéal, tout composant devrait être testé unitairement en isolation ; personnellement, je ne suis pas obsédé par l'isolation lorsque l'objet qui doit être testé n'a pas de dépendances tierces. Tester plusieurs objets à l'unisson m'importe peu du moment que tous les cas de test sont couverts.

Nous allons tester le composant Façade (IdentityService) dans son intégralité. Nous allons créer une instance de XMLEndPoint mockée lorsque nous instancierons IdentityServiceImpl. Cela oblige le code qui envoie les requêtes HTTP à être isolé du test2 suivant :

xmlEndPoint = mock(XmlEndPoint.class);
identityService = new IdentityServiceImpl(xmlEndPoint);

A partir de là, l'instance de XmlEndPoint mockée va devoir se comporter en fonction des différentes conditions, de manière à ce que nous puissions identifier les comportements de IdentityService en conséquence. En prenant "Find user" pour exemple, XmlEndPoint est documenté pour faire ce qui suit :

  1. Lorsque l'utilisateur est trouvé : le code statut HTTP sera 200 et le corps de la réponse contiendra les informations concernant l'utilisateur en XML ;
  2. Lorsqu'il ne l'est pas, le code statut HTTP sera 204 et le corps de la réponse sera vide

Dans le premier cas ("utilisateur trouvé"), nous attendons que la méthode get de XmlEndPoint retourne une réponse dont le statut est 200 et dont le corps contient les informations de l'utilisateur en XML :

when(xmlEndPoint.get(anyString())).thenReturn(
    new XmlEndPointResponse(STATUS_SUCCESS, userFoundResponse));

Lorsque l'instance de XmlEndPoint mockée est mise en place ainsi, l'opération "rechercher l'utilisateur" sera capable de trouver un utilisateur et de créer l'instance de client correcte :

Customer customer = identityService.findByEmail("gigix1980@gmail.com");
assertThat(customer.getFirstName(), equalTo("Jeff"));
assertThat(customer.getLastName(), equalTo("Xiong"));

userFoundResponse est une chaîne de caractères contenant les informations sur l'utilisateur au format XML. Lorsque cette chaîne est retournée par XmlEndPoint, IdentityService la convertit en instance de Customer. A ce point, nous avons vérifié qu'IdentityService (et les objets dont il dépend) se comporte correctement.

Le second cas ("utilisateur non trouvé") est testé de manière similaire :

@Test
public void shouldReturnNullWhenUserDoesNotExist() throws Exception {
    when(xmlEndPoint.get(anyString())).thenReturn(
        new XmlEndPointResponse(STATUS_NO_CONTENT, null));
    Customer nonExistCustomer =
        identityService.findByEmail("not.exist@gmail.com");
    assertThat(nonExistCustomer, nullValue());
}
Other methods of IdentityService also can be tested similarly.

Tests d'intégration

Après avoir achevé les deux niveaux de tests décrits ci-dessus, nous avons déjà couvert tous les cas pour les cinq composants de l'interface. Mais ne baissez pas la garde : 100% de couverture ne signifie pas que nous avons couvert tous les endroits où une erreur peut survenir. Par exemple, il subsiste deux emplacements qui n'ont pas encore été vérifiés :

  • La disponibilité de l'URL des services distants réels
  • Si le comportement de ces services est aligné avec le document

Ces deux éléments doivent être testés en environnement réel. De plus, pour les cas de test de ceux-ci, il est plus important de décrire la fonctionnalité que de vérifier la justesse. Il y a deux raisons à celà. D'une part, les services distants changent rarement ; d'autre part, lorsque les services distants ont des erreurs (comme celle d'être indisponible), il n'y a rien à faire. De fait, la valeur des tests d'intégration qui touchent les services réels est d'offrir un document précis et exécutable.

Afin d'y parvenir, nous devrions éviter d'utiliser nos propres interfaces (comme IdentityService ci-dessus) dans l'espoir que les tests automatisés nous indiquent la provenance des erreurs : les services distants ou notre propre application. Je préfère utiliser des librairies standards de bas niveau pour accéder à ces services :

System.out.println("=== 2. Find that user out ===");
GetMethod getToSearchUser = new GetMethod(
    configuration.getUrlForSearchUser("gigix1980@gmail.com"));
getToSearchUser.setRequestHeader("Accept", "application/xml");
httpClient.executeMethod(getToSearchUser);
assertThat(getToSearchUser.getStatusCode(), equalTo(200));
System.out.println(getResponseBody(getToSearchUser));

Dans ce cas de test, nous utilison Apache Commons HTTP Client pour initier les requêtes réseaux. Pour la réponse, il n'est pas nécessaire de la vérifier, mais uniquement de confirmer que les services sont disponibles et d'écrire le corps de la réponse (au format XML) pour l'utiliser comme référence. Comme discuté ci-dessus, nous attendons des tests d'intégration qu'ils décrivent le comportement des services tiers plutôt que de vérifier leur justesse. Ces cas de tests sont suffisants pour agir en tant que "document exécutable".

Intégration continue

Nous avons vu différents types de tests maintenant. Seuls les tests d'intégration communiquent avec les services tiers, ce qui en fait les tests les plus longs. Heureusement, il n'est pas nécessaire d'exécuter les tests d'intégration aussi souvent que les autres tests, car ils décrivent uniquement le comportement des services tiers, les fonctionnalités de notre propre code étant couvertes par les tests des extrémités de réseaux (en utilisant Moco) et par les tests unitaires des autres composants.

Maven peut nous aider à gérer cette situation. Maven définit deux phases dans son cycle de vie: test et integration-test. Il existe un plugin nommé "Failsafe" :

Le Plugin Failsafe est conçu pour exécuter des tests d'intégration alors que le Plugin Surefire l'est pour celle des tests unitaires. Le nom (failsafe) a été choisi à la fois parce qu'il est un synonyme de surefire et parce qu'il signifie que lorsqu'il échoue, il le fait de manière sûre.

Maven recommande d'exécuter les tests unitaires avec Surefire et les tests d'intégration avec Failsafe. De fait, nous placerons tous les tests d'intégration dans un package appelé "integration" et nous modifierons la configuration Surefire dans le pom.xml pour exclure ce package :

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${maven-surefire-plugin.version}</version>
    <executions>
        <execution>
            <id>default-test</id>
            <phase>test</phase>
            <goals>
                <goal>test</goal>
            </goals>
            <configuration>
                <excludes>
                    <exclude>**/integration/**/*Test.java</exclude>
                </excludes>
            </configuration>
        </execution>
    </executions>
</plugin>

Puis nous ajoutons la configuration suivante pour exécuter les tests d'intégration avec Failsafe :

<plugin>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.12</version>
    <configuration>
        <includes>
            <include>**/integration/**/*Test.java</include>
        </includes>
    </configuration>
    <executions>
        <execution>
            <id>failsafe-integration-tests</id>
            <phase>integration-test</phase>
            <goals>
                <goal>integration-test</goal>
            </goals>
        </execution>
        <execution>
            <id>failsafe-verify</id>
            <phase>verify</phase>
            <goals>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Maintenant, la commande "mvn test" n'exécutera pas les tests d'intégration ; et la commande "mvn integration-test" exécutera à la fois les tests unitaires et les tests d'intégration. Nous pouvons créer deux jobs dans notre serveur d'intégration continue (p.e. Jenkins) : l'un est déclenché par chaque commit et exécute tout sauf les tests d'intégration, l'autre s'exécute une fois par jour, et lance l'intégralité de la construction. Nous avons obtenu un équilibre entre la vitesse et la qualité : chaque commit déclenche une construction qui couvre tout le fonctionnel, ce qui est rapide et indépendant de la disponibilité des services tiers ; la construction quotidienne couvre tous les services tiers, elle nous renseigne sur le dernier statut des services tiers.

Refactorer le système existant

En suivant le cadre mentionné ci-dessus pour concevoir les interfaces, il est aisé de garantir la testabilité d'un système. Toutefois, système existant (qui n'est pas bien conçu et n'a pas la notion logique d'extrémité de réseau) couple la logique de communication distante avec d'autres logiques. Il est malaisé d'écrire des tests spécifiques pour la communication réseau réelle, car ces tests initieraient beaucoup de requêtes réseau, ce qui rendrait la construction lente et aléatoire.

L'exemple suivant est une structure de code très répandue, qui couple plusieurs responsabilités : la préparation du corps de la requête, l'initialisation de la requête et la gestion de la réponse.

PostMethod postMethod = getPostMethod(velocityContext, templateName, soapAction);
new HttpClient().executeMethod(postMethod);
String responseBodyAsString = postMethod.getResponseBodyAsString();

if (responseBodyAsString.contains("faultstring")) {
    throw new WmbException();
}
Document document;
try {
    LOGGER.info("request:\n" + responseBodyAsString);
    document = DocumentHelper.parseText(responseBodyAsString);
} catch (Exception e) {
    throw new WmbParseException(
        e.getMessage() + "\nresponse:\n" + responseBodyAsString);
}

return document;

Ce code pourrait apparaitre dans chaque méthode utilisée pour s'intégrer avec les services tiers, et il s'agit d'une duplication, un type d'indice de mauvais code. Mais la duplication dans ces méthodes n'est pas très évidente, car la logique de chaque méthode (comme la préparation du corps de la requête, la gestion de la réponse, etc.) est différente. Par exemple, le code ci-dessus utilise Velocity pour générer le corps de la requête et JDOM pour analyser la réponse. Même les outils d'inspection de code automatisée (comme Sonar) ne peuvent les trouver.

Après avoir appliqué quelques approches de refactoring comme l'Extraction de Méthodes, l'Ajout de Paramètres, la Suppression de Paramètres, nous pouvons restructurer le code ainsi :

// 1. prepare request body
String requestBody = renderTemplate(velocityContext, templateName); 
// 2. execute a post method and get back response body
PostMethod postMethod = getPostMethod(soapAction, requestBody);
new HttpClient().executeMethod(postMethod);
String responseBody = postMethod.getResponseBodyAsString();
if (responseBodyAsString.contains("faultstring")) {
    throw new WmbException();
}
// 3. deal with response body
Document document = parseResponse(responseBody);
return document;

La duplication est maintenant plus apparente dans le second bloc. Le livre "Refactoring(http://www.amazon.co.uk/Refactoring-Improving-Design-Existing-Technology/dp/0201485672/ref=sr_1_1?ie=UTF8&qid=1370253792&sr=8-1&keywords=Refactoring)" décrit ce scénario3 :

Si du code est dupliqué dans deux classes indépendantes, pensez à utiliser l'Extraction de Classe dans l'une des classes et à utiliser le nouveau composant dans l'autre. Une autre possibilité est que la méthode appartienne vraiment à l'une des classes uniquement et doive être invoquée par l'autre classe ou bien qu'elle appartienne à une troisième classe qui doive être référencée par les deux classes originelles. Vous devez décider où la méthode fait du sens et vous assurer qu'elle soit là et nulle part ailleurs.

C'est la situation à laquelle nous faisons face, et c'est le moment d'introduire le concept "d'extrémité réseau". En utilisant l'Extraction de Méthode et l'Extraction de Classe, nous créerons une nouvelle classe SOAPEndPoint :

public class SOAPEndPoint {
    public String post(String soapAction, String requestBody) {
        PostMethod postMethod = getPostMethod(soapAction, requestBody);
        new HttpClient().executeMethod(postMethod);
        String responseBody = postMethod.getResponseBodyAsString();
        if (responseBodyAsString.contains("faultstring")) {
            throw new WmbException();
        }
        return responseBody;
    }
}

Le code originel utilisera la nouvelle classe SOAPEndPoint :

// 1. prepare request body
String requestBody = renderTemplate(velocityContext, templateName); 


// 2. execute a post method and get back response body
// SOAPEndPoint is dependency injected by Spring Framework
String responseBody = SOAPEndPoint.post(soapAction, requestBody);

// 3. deal with response body
Document document = parseResponse(responseBody);
return document;

En suivant la stratégie de test ci-dessus, nous devrions ajouter des tests pour SOAPEndPoint avec Moco. Franchement, la logique de SOAPEndPoint est très simple : envoyer les requêtes POST avec le contenu spécifié à l'URL spécifiée ; lancer une exception si le corps de la réponse contient la chaîne "faultstring" ; sinon, retourner la chaîne directement. Bien que le nom de la classe soit SOAPEndPoint, la méthode "post" n'est pas concernée par le fait de savoir que la requête/réponse suive le protocole SOAP, et de fait la chaîne retournée par Moco n'a pas besoin d'être conforme au protocole SOAP pendant les tests, à la fois lorsque le corps de la réponse contient la chaîne "faultstring" et lorsque ce n'est pas le cas.

De là, vous pouvez vous demander pourquoi la classe s'appelle SOAPEndPoint. La réponse est que dans la méthode getPostMethod (qui n'est pas présentée ici), il est nécessaire de remplir quelques en-têtes HTTP, et ces derniers sont pour la plupart en relation avec les Services Web fournis par les services tiers avec lesquels il faut s'interfacer. Ces en-têtes sont adaptées aux méthodes de service côté client, de telle manière qu'elles puissent être extraites dans une méthode commune : getPostMethod.

Ensuite, nous pourrions écrire des tests d'intégration descriptifs, et utiliser des techniques de mocking pour s'assurer qu'aucune référence à SOAPEndPoint n'initie des requêtes réseau.

Maintenant, nous avons terminé le refactoring de toutes les interfaces, et créé un groupe de tests suivant notre stratégie. Continuer le refactoring pour séparer le Constructeur de Requête et l'Analyseur de Réponse est laissé comme exercice au lecteur.

Conclusion

La construction d'une application web Java EE qui s'appuie fortement sur des services tiers a tendance à devenir lente et peu fiable, à cause de ses dépendences à ces services tiers. Nous avons identifié un modèle pour implémenter des interfaces. En utilisant ce modèle et la stratégie de test associée, avec l'aide de Moco, nous sommes parvenus à isoler nos tests des services tiers et nous avons rendu notre construction plus rapide et plus fiable.

Nous nous sommes également intéressés à certaines implémentations existantes d'interfaces, et nous les avons refactorées dans le modèle afin d'appliquer également la stratégie de test au code existant. Ceci prouve que la stratégie fonctionne d'une manière universelle : même un système historique peut réussir à implémenter le découplage et à isoler les tests en adoptant les techniques de refactoring.

Plus sur Moco

Au bureau de ThoughtWorks à Chengdu, nous développons une application en-ligne pour une société financière. Cette application nécessite inévitablement d'énormes quantités de travail d'intégration car toutes les données et les règles métier principales sont stockées dans des systèmes COBOL. La plupart des équipes dans le bureau se plaignent que les cas de test deviennent lents et peu fiables en raison de l'intégration avec des serveurs distants. Afin d'y remédier, mon collègue Zheng Ye a créé deux frameworks Moco pour simplifier les tests d'intégration.

En dehors du mode API que nous avons déjà vu dans les cas de test ci-dessus, Moco supporte également un mode autonome, dont l'objectif est de créer un serveur de test rapidement. Par exemple, la configuration suivante (située dans un fichier "foo.json") décrit un serveur HTTP basique :

[
  {
    "response" : {
      "text" : "Hello, Moco"
    }
  }
]

Démarrer le serveur :

java -jar moco-runner-<version>-standalone.jar start -p 12306 -c foo.json

Si vous accédez à n'importe quelle URL en-dessous de "http://localhost:12306", "Hello Moco" sera affiché à l'écran. Nous sommes capables de simuler n'importe quel serveur distant avec lequel nous allons nous interfacer, et de l'équiper pour le développement local et le test fonctionnel.

Grâce au pouvoir de la communauté open source, Moco a un plugin Maven fourni par Garrett Heel, un développeur australien. Avec son aide, nous sommes capables d'intégrer facilement Moco dans notre processus de construction Maven, et de démarrer ou d'arrêter le serveur Moco en fonction de nos besoins (par exemple, démarrer le serveur Moco avant les tests fonctionnels Cucumber et l'arrêter après qu'ils soient terminés).

En ce moment, Moco est utilisé dans plusieurs projets dans les bureaux de ThoughtWorks à Chengdu. Le développement est encore en cours et basé sur les nouvelles exigences fournies par ces projets. Si vous êtes intéressés par Moco, n'hésitez pas à nous envoyer des suggestions d'amélioration ou à y contribuer.

A propos des Auteurs

Jeff Xiong est chef de service à ThoughtWorks Chengdu. Il est également développeur d'applications d'entreprise avec plus de 10 années d'expérience.

David Yin est développeur Java et compte plus de 6 années d'expérience. C'est un passionné de nouvelles technologies et de méthodologies. Il travaille maintenant à ThoughtWorks en tant que consultant.

Pengfei Cui est développeur à ThoughtWorks, un programmeur qui adore éliminer du code. Il éclaire trois mètres cube autour de lui uniquement avec sa tête.

1 Dans ce contexte, "construction" indique "un processus qui génére un livrable applicatif à partir de code source en utilisant des outils d'automatisation". Un processus normal de construction pour les applications Java EE inclut les phases de compilation, de vérification statique de qualité de code, de test unitaire, de test d'intégration, de paquetage, de test fonctionnel, etc. 2 Nous utilisons Mockito pour mocker les dépendances dans les tests unitaires 3 Martin Fowler et al, Refactoring, chapter 3.1.

Evaluer cet article

Pertinence
Style

Contenu Éducatif

BT