Thématiques principales

Affichage des articles dont le libellé est Travis. Afficher tous les articles
Affichage des articles dont le libellé est Travis. Afficher tous les articles

mercredi 21 février 2018

Intégration continue

Petit aparté pour parler un peu de l'intégration continu. Nous avions évoqué un peu le sujet dans l’article précédent [1] sur Gradle qui en est tout comme Maven [2] un élément et outil central à la construction d’un composant logiciel. Cependant, si nous avions décrit son rôle dans le processus de développement, nous n'avons pas décrit qu’elles sont les autres outils qui peuvent nous aider a automatiser l’ensemble du processus, nous aider à mener à bien l’entreprise de production logiciel complet, de A a Z.

Contextualisation

Repartons d’un processus de développement de base. Nous en avions vu quelques un dans l’article [3]. En voici un, sûrement perfectible, dans lequel nous utilisons une approche agile au sein de laquelle vont intervenir nos outils d'intégration continue.




Sans forcément faire un long discours explicatif des différents éléments de ce schéma (qui n’est qu’un modèle parmi d’autres possibles), nous pouvons décrire ce processus comme suit:

A partir de l’idée du client, sont définies un certain nombre de spécifications fonctionnelles plus ou moins raffinées. Ces spécification sont injectées, une fois suffisamment mature et dont la valeur ajoutée est considérée comme suffisamment significative, dans un certain nombre de Sprint sous la forme de Stories fonctionnelles et ou techniques. Le but final de l’approche étant de produire un certain nombre d'artefacts évoluant au fil d’un certain nombre de versions

Différents acteurs cités ici ont des rôles spécialisés selon les différents axes majeurs du développement logiciels :

  • axe fonctionnel : le PO
  • axe technique : l’architecte
  • axe process : le scrum master
  • axe IVQ : le responsable IVQ (Intégration Validation Qualification)
  • axe savoir faire : le développeur
La collaboration de ces différents acteurs est primordiale (et a mon sens, l’absence de l’un d’eux ne peut que mener à un désastre mais nous y reviendrons lorsque nous traiterons de la combinatoire de leur activités).

Nous avons déjà parler de l’approche agile mais nous pouvons constater ici qu’une phase importante du processus concerne la sortie de la partie cyclique. Cette phase peut être appeler livraison car elle correspond à la finalisation du ou des développements, et correspond au final à la livraison d’un nouvel incrément fonctionnel par l’ajout de nouveaux morceaux de code. Il faut comprendre que cette phase n’est pas terminale mais itérative comme l’est le développement et consiste à soutenir le développement en permettant la validation/livraison a chaque itération.

L'integration Continue

Cette phase est en fait appeler la phase d’intégration continue. Elle provient du besoin de tester systématiquement le code source et les nouvelles fonctionnalités apportées tout en garantissant la non régression des fonctionnalités déjà développées précédemment.


Mot d'ordre : automatisation

Dans ce schéma, le processus d'intégration continu fait intervenir un ensemble de composants en interaction et répondant à différents besoins. En entrée de l'intégration continu nous avons l’outil de gestion des sources (tel que Git [4], SVN [5] ou Mercurial [6]) dans lequel les développeurs déposeront le code produit et tester localement unitairement.

Ceci n’est cependant clairement pas suffisant car si un ajout de code peut être correct sur le poste du développeur et même en considérant que ce poste est conforme à un standard commun à toute l'équipe, il persistera toujours des différences sans compter les différences évidentes entre le poste de dev et la configuration d’un serveur cible.


Feed-back

Pour résoudre ces problèmes, intervient alors la phase d'intégration continu. Elle va permettre de procéder à une construction complète, automatisé et régulière de l’ensemble du composant logiciel soit de façon journalière, soit a chaque modification du référentiel de code, voir les deux. En procédant ainsi, l'intégration continu permettra la validation dans des plateforme de référence, de l’ensemble de fonctionnalités en déroulant l’ensemble des tests prévus (à noter que ces tests sont définis selon des niveaux différents, N1: tests unitaires, N2 tests d'intégrations, N3 : tests fonctionnels; les niveaux N2 et N3 sont souvent fusionnés). Les tests une fois validés, les développement réalisés par les développeurs sont alors intégré ensemble au sein d’une même branche ou de nouvelles validations sont déroulées (voila le coté intégration en continu).

Dans les faits, les sources sont récupérées par un outil d'orchestration tel que Jenkins [7] ou Travis [8] qui par configuration va appliquer un certain nombre de processus via un outil de build comme maven ou gradle ou directement sur la branche contenant les sources.

Procéduralement l’outil d’orchestration va devoir:

  • construire le composant (via maven [9] ou gradle [10]) en s’appuyant sur un entrepôt de composant (artifactory [11] ou nexus [12])
  • utiliser les éléments produit pour effectuer des tests unitaires
  • utiliser les éléments produit pour effectuer des tests fonctionnels dans un plateforme cible (virtuelle VM/docker ou non) avec des outils tels que robotframework [13] , sikuli [14]
  • effectuer de l’analyse de code à l’aide d’un outil comme sonar [15]
  •  produire de la documentation à l’aide d’outils comme maven site [16] ou java doc [17]


Vers le continuous delivery et le DevOps

En parallèle de cette approche ou le but est de vérifier au plus tôt l’absence de défauts mais aussi de problème d'intégration, il est considéré aujourd’hui de nouvelles approches par l’utilisation de conteneur versionable et livrable directement au client.

Ces nouvelles approches permettent au développeur de disposer d’un environnement de test ( voir de développement) local beaucoup plus proche et conforme à ce que sera la cible chez le client. Ces approches portées par des logiciels comme Docker fournissent des moyens beaucoup plus simple et élémentaires de validation et d'intégration en rapprochant le développeur de la plateforme cible cependant, elle nécessite l’utilisation par le client d’architecture spécifique basé sur ce type de conteneur. 


Facilitant d’un coté la maintenance, ces solutions doivent malgré tout, “en solution de virtualisation”, fournir des moyens de sécurisation et d’optimisation des performances au moins équivalentes aux solutions conventionnelles.

Conclusion

Dans ce blog, nous avons déjà traité des sujets tels que Docker. Il ne fait aucun doute que ce type de technologies ont leur adepte, et à juste titre. Cependant, même si ces approches ont leur avantages, il me semble que les approches conventionnelles (parce que omniprésente) gardent elles aussi leur points forts et que les solutions de productions logicielles futurs devront surtout composer avec des approches mixtes.

Il n’en reste pas moins que l'intégration continu est un environnement fortement outillé. Certains de ces outils, comme Maven, Gradle ou même la production documentaire, ont été évoqué dans différents articles. Pour les prochains articles, afin d’affiner notre vision des possibilités de l'intégration continu et des architectures possible la guidant, nous tacherons de rentrer un peu plus dans le détails de ces autres outils

References

[1] http://un-est-tout-et-tout-est-un.blogspot.com/2018/01/gradle.html
[2] http://un-est-tout-et-tout-est-un.blogspot.com/2017/12/maven-introduction.html
[3] http://un-est-tout-et-tout-est-un.blogspot.com/2017/12/les-processus-de-developpement-ou.html
[4] https://git-scm.com/
[5] https://subversion.apache.org/
[6] https://www.mercurial-scm.org/
[7] https://jenkins.io/
[8] https://travis-ci.org/
[9] https://maven.apache.org/
[10] https://gradle.org/
[11] https://jfrog.com/artifactory/
[12] https://www.sonatype.com/nexus-repository-sonatype
[13] http://robotframework.org/
[14] http://www.sikuli.org/
[15] https://www.sonarqube.org/
[16] https://maven.apache.org/plugins/maven-site-plugin/
[17] https://maven.apache.org/plugins/maven-javadoc-plugin/

mardi 30 janvier 2018

Test d'IHM : fest-util

Effectuer des tests unitaires est une tâche indispensable mais qui peut souvent s'avérer un vrai casse tête lorsqu’il s’agit de traiter des IHM.

En Java standard il existe une librairie de test dédiée au IHM de type client lourd pour les API swing et awt qui s’appele Fest [1] [3]. Celle est vraiment concu pour etre simple et logique en utilisant les noms des éléments de l’IHM pour se mapper sur leur interfaces de fonctionnement.

Pour l’utiliser il suffit de tirer l'artefact suivant:
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-util</artifactId>
<version>1.1.6</version>
<scope>test</scope>
</dependency>
Pour l’utiliser il reste à définir une classe de test classique JUnit héritant de la classe FestSwingJUnitTestCase dans laquelle il faudra initialiser un robot Fest et le donner à un objet de type FrameFixture qui va se charger de piloter le robot afin que celui ci parse et effectuer les interaction adéquate sur notre IHM.

Avant cela, Pour que le robot soit capable de parser notre IHM il faudra par contre indiquer a Fest sur quel IHM il doit faire ses actions (grâce a un GuiQuery). On spécifie alors une méthode statique d’initialisation dédié dans laquelle nous instancierons notre IHM:
@RunsInEDT
private static MainFrame createNewEditor(BundleContext context) {
final GuiQuery<MainFrame> query = new GuiQuery<MainFrame>() {
@Override
protected MainFrame executeInEDT() {
MainFrame app = null;
try {
app = new MainFrame(context);
} catch (final TcOsgiException e) {
e.printStackTrace();
}
return app;
}
};
return GuiActionRunner.execute(query);
}
Du coup, il nous faudra initialiser dans un setUp notre environnement de test contenant le FrameMixture:
@Override
protected void onSetUp() {
try {
BundleContext context = Mockito.mock(BundleContext.class);
editor = new FrameFixture(robot(), MainFrameTest.createNewEditor(context));
editor.show();
} catch (Exception e) {
e.printStackTrace();
}
}
Grace a cela, il ne nous restera plus qu’a declarer les actions que l’on souhaitera faire sur l’IHM dans des tests spécifiques comme on le ferait dans un test unitaire classique sauf que la nous allons scénariser les actions:
@Test
public void profilCreationSelection() {
editor.menuItem("Select MorphMath Action").click();
editor.comboBox("combo1").selectItem("dilatation").click();
editor.menuItem("GO").click();
System.out.println(new File(".").getAbsolutePath());
editor.fileChooser().fileNameTextBox().setText(
"docvierge.bmp");
editor.fileChooser().approve();
Thread.sleep(500);
editor.close();
}
A noter qu'à ce niveau d’abstraction, nous ne sommes plus vraiment en train de faire des tests unitaires mais plutôt des tests fonctionnels mais cela n’a pas forcement d’importance dans notre cas (a noter malgré tout que l’approche est particulièrement adapté à la mise en place de test pour vérifier des cas d’utilisation particulière en lien direct avec le besoin utilisateur)

Voila un petit aperçu de Fest et de ses capacités pour des tests d’IHM. Point particulier a prendre en compte lors de l'exécution des tests: ces derniers sont réalisés avec une IHM visible vous permettant de voir quels sont les actions et mouvement de souris réalisées pour faire le test. Cela est clairement intéressant mais comporte un inconvénient majeur, vos tests ne fonctionnent pas sans environnement graphique comme dans un serveur d'intégration continu. Typiquement vous aurez une erreur du type (dans Travis [2] par exemple):

PM org.fest.swing.monitor.WindowStatus <init>
WARNING: Error ocurred when creating a new Robot
java.awt.AWTException: headless environment
at java.awt.Robot.<init>(Robot.java:91)
at org.fest.swing.util.RobotFactory.newRobotInPrimaryScreen(RobotFactory.java:35)
at org.fest.swing.monitor.WindowStatus.<init>(WindowStatus.java:58)
at org.fest.swing.monitor.WindowStatus.<init>(WindowStatus.java:51)
at org.fest.swing.monitor.WindowMonitor.<init>(WindowMonitor.java:51)
at org.fest.swing.monitor.WindowMonitor$SingletonLazyLoader$1.executeInEDT(WindowMonitor.java:134)
at org.fest.swing.monitor.WindowMonitor$SingletonLazyLoader$1.executeInEDT(WindowMonitor.java:132)
at org.fest.swing.edt.GuiQuery.run(GuiQuery.java:41)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Pour résoudre ce problème il vous suffira d’utiliser xvfb (un server X11) [4] . Comme décrit dans [5], cela permet de simuler un environnement graphique. (ou un autre exemple [6]).

References:

[1] http://www.vogella.com/tutorials/FEST/article.html
[2] https://travis-ci.org/
[3] http://tuhrig.de/automated-ui-testing-with-swing-fest/
[4] https://www.x.org/archive/X11R7.6/doc/man/man1/Xvfb.1.xhtml
[5] https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI
[6] https://gist.github.com/cecilemuller/764afa5d4c67e17741d9bc258b45cdc1