dimanche 23 octobre 2011

plan de test multi-langages depuis Java

Problématique
Voici quelques mois, un collègue me demanda si la conception d'un plan des tests était facile.
Bien évidemment, il y a plein d'outils pour gérer des tests unitaires et des plans de tests, JUnit en tête ( et même via Ant :D )
Le soucis résidait au fait qu'il fallait lancer des scripts qui lancent d'autres scripts. Ce sont ceux-là qu'il fallait gérer. Plus tard, l'intégration dans une interface graphique devint nécessaire.
Moins trivial que cela donc, il fallait concevoir un outil. Quelques nuits passées sur le sujet, à essayer de gérer les codes retours rendus par l'invite DOS me persuadèrent de la difficulté. Les nuits portent conseils, ceux-ci furent pourtant long à venir.

Il a bon DOS celui-là
Vous trouverez sur Internet de nombreux conseils sur comment récupérer les codes retours du DOS. Malheureusement, la situation n'est pas universelle suivant les versions de Windows. Pas mal de recherches dans un navigateur ne sont pas forcément valables.
Chose étonnante, si lé récupération du code DOS est erratique en Java, la récupération d'un code Python et autre informations est d'une conformité confondante aux standards Java. Encore une enigme microsoftienne de plus.
Voici ci-après quelques copies d'écran concernant les développements en cours.

Rassembler le patchwork applicatif
  • l'interface graphique attendue avec les fonctionnalités de création, modification, exécution, suppression et historique des plans de tests.
  • les traitements sur les plans de tests
  • la création des tests unitaires successifs, conditionnés
  • l'affichage des historiques grâce aux fonctions java 6 natives.
Conclusion rapide
Les développements étant encore en phase d'ébauche, je ne donnerai pas plus d'informations concernant cet n-ième outil. La seule chose que je puisse affirmer, c'est qu'il fonctionne très bien ;) Reste à le rendre ergonomique.

vendredi 3 juin 2011

Les Get Setteurs ne sont pas classe

Etes-vous déjà retrouvés face à un graphe UML qui est compliqué du fait de la présence des méthodes getter et Setter des attributs privés ? Cela vient de m'arriver en manipulant une archive War. Le graphe serait tellement plus simple sans les méthodes dédiées.

Guetter les getter et sauter les setter

 Une petite verrue pour recenser les attributs et méthodes dédiées devrait faire l'affaire pour éviter de trop modifier mon générateur basé sur Graphviz. Mais en réalité, c'est plus complexe que cela.
    // -------------------------------------------
    void manageGetSet() {
        int f;
        int m;
        Field fi[] = {};
        try {
            fi = c.getDeclaredFields();
        } catch (Error e) {
        }
        for (f = 0; f < fi.length; f++) {
            boolean hasGet = false;
            boolean hasSet = false;
            String nomChamp = fi[f].getName();
            String nomChampGet = "get" + nomChamp.toUpperCase().substring(0, 1)
                    + nomChamp.substring(1);
            String nomChampSet = "set" + nomChamp.toUpperCase().substring(0, 1)
                    + nomChamp.substring(1);
            Method mi[] = {};
            try {
                mi = c.getDeclaredMethods();
            } catch (Error e) {
            }
            for (m = 0; m < mi.length; m++) {
                String methodName = mi[m].getName();
                if (methodName.compareTo(nomChampGet) == 0) {
                    hasGet = true;
                }
                if (methodName.compareTo(nomChampSet) == 0) {
                    hasSet = true;
                }
            }
                if (hasSet && hasGet) {
                    vGetSetFields.add(nomChamp);
                    vGetSetMethods.add(nomChampGet);
                    vGetSetMethods.add(nomChampSet);
                } else

                if (hasGet) {
                    vGetSeulFields.add(nomChamp);
                    vGetSeulMethods.add(nomChampGet);
                }
            }
        }
    // -------------------------------------------

Tester

Voici un exemple tiré des showcase de Primefaces.
Le premier schéma indique le modèle sans distinguer getter et setter, le deuxième permet quant à lui de les distinguer.
  • Version brute

  • version améliorée

Petit constat

  • le jaune n'est pas généré par Graphviz, - pas encore trouvé comment faire - il permet juste de visualiser les différences notables.
  • deux blocs supplémentaires figurent sur le graphe, un bloc "get set" tout en haut, un bloc "get seul" juste en dessous. Les blocs vides ont été noircis.
  • c'est améliorable, surtout quand la manipulation des couleurs sera possible dans les records Graphviz.
  • le graphe est plus compact, il le serait moins si le graphe ne contenait pas des beans java.
  • vérifier la faisabilité avec yED.

Liens

mercredi 16 mars 2011

yED, I can !

Un rapide billet concernant un outil de génération de graphe un peu plus "propre" que graphviz, c'est à dire un générateur de graphe qui restitue des liens avec une bonne lisibilité.
Pour cela, j'ai utilisé l'outil yED, fournissant un éditeur freeware prenant en entrée différents types de formats de graphes ou permettant tout simplement de les dessiner ... à essayer absolument.
Contrairement à Graphviz, le passage à l'éditeur permet de formater les schémas à façon. Il "spacialise" le graphe.
Mon outil de rétro-conception UML http://sylvainspeh.blogspot.com/2010/07/retro-conception-uml-de-classes-java.html devrait donc bientôt s'enrichir d'une sortie supplémentaire.

Extrait du format GML

Le format GML, suffisamment concis, ressemblant à celui de graphviz, est utilisé pour afficher le graphe.

Types de graphes avec yED

Graphe hiérarchique

Graphe façon UML

Pour concevoir ce graphe, une application java a été conçue pour générer 12 "classes". Pour chacune de quelques associations UML communes ( héritage, association, composition, utilisation, implémentation et agrégation ), le programme veille à ne pas associer 2 mêmes classes avec des liens différents, pour 4 liens de chaque type.

vendredi 19 novembre 2010

Découvrir et lancer les classes d'un jar ayant une méthode "main"

Introduction

Encore une utilité de l’introspection : afficher les classes disposant d'une méthode "main" dans un jaret offrir la possibilité de la lancer. C'est bien pratique quand on ne veut pas lancer la main-class du manifest.

Méthode

  • Référencer le jar dans un classLoader
  • Parcourir les entrées du jar pour ne prendre que les classes ayant une méthode publique, statique dénommée "main"
  • Les afficher par exemple dans un ordre chronologique

Extrait de code concernant l’extraction

File f = new File(location);
loader = new URLClassLoader(new URL[] { f.toURI().toURL()  } );
JarFile jf = new JarFile(location);
Enumeration e = jf.entries();
JarEntry je = null;
for( int j=0 ; e.hasMoreElements() ; j++ )
      {
      je = (JarEntry)e.nextElement();
//---------------------------------------------
public static boolean hasPublicStaticVoidMainMethod ( Class _c )
{
      Method [] publicMethods = _c.getMethods() ;
      for ( Method uneMethode : publicMethods )
      {
            int m = uneMethode.getModifiers() ;
            if ( ( Modifier.isPublic(m) ) && ( Modifier.isStatic(m) ) && ( uneMethode.getReturnType().toString().compareTo("void") == 0 ) && ( uneMethode.getName().compareTo("main") == 0 ) )
            {
                  return true ;
            }
      }
      return false ;
}
//---------------------------------------------

Extrait de code concernant l'invocation de la méthode

Class c = Class.forName(s);
Class[] argTypes = new Class[] { String[].class };
Method main = c.getDeclaredMethod("main", argTypes);
String[] mainArgs = {} ;
main.invoke(null, (Object)mainArgs);

Copies d’écrans correspondantes


Exemple concernant rt.jar


dimanche 19 septembre 2010

Rétro-conception de Design Patterns java

Objectif

être capable de retrouver des Design Patterns éprouvés dans des classes Java.

Intérêt

Même si de nos jours les outils de rétro-conception savent très bien passer de classes java à des diagrammes UML, un pas supplémentaire peut être fait en retrouvant les Design Patterns noyés anonymement dans des schémas. Un niveau d'abstraction supplémentaire serait donc le bienvenu.

Bonnet blanc et blanc bonnet

Il existe en fait de nombreuses façons de concevoir ces Design Patterns, avec des variantes mineures, qui font tout le charme des algorithmes visant à retrouver les 3 types de DP ( construction, structuration, comportement ). Un groupe connu sous le nom de "bande des quatre" ( Gang of four en Anglais ) est cité sur le site de SUN comme étant le premier à s'être penché sur le problème.
Cependant, l'expérience a prouvé que les concepteurs de SUN n'avaient pas toujours suivi ces bonnes pratiques standard.

Cas du Pattern "Singleton"

Il nécessite :
  • un constructeur privé
  • une méthode d'instance
  • un attribut d'instance

Exemple du pattern Singleton :

public class Singleton
{
    /** Récupère l'instance unique de la class Singleton.<p>
     * Remarque : le constructeur est rendu inaccessible
     */
    //---------------------------------------------  
    public static Singleton getInstance()
    {
        if (null == instance)
        { // Premier appel
            instance = new Singleton();
        }
        return instance;
    }
    //---------------------------------------------
    /** Constructeur redéfini comme étant privé pour interdire
     * son appel et forcer à passer par la méthode <link
     */
    private Singleton()
    {
    }
    //---------------------------------------------
    /** L'instance statique */
    private static Singleton instance;
    //---------------------------------------------
}

Exemple de code pour le détecter :

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class CheckSingleton
{
    boolean debug = false ;
    //---------------------------------------------
    public CheckSingleton( String _className )
    {
        traiter(_className) ;
    }
    //---------------------------------------------
    boolean hasNoPublicConstructor ( Class _c )
    {
        boolean b = false ;
        Constructor[] publicConstructeurs = _c.getConstructors();
        if ( publicConstructeurs.length == 0 )
        {
            b = true ;
            if ( debug )
                System.out.println( "hasNoPublicConstructor" ) ;
        }
        return b ;
    }
    //---------------------------------------------
    boolean hasSomePrivateConstructor ( Class _c )
    {
        boolean b = false ;
        Constructor[] tousConstructeurs = _c.getDeclaredConstructors();
        for ( Constructor unConstructeur : tousConstructeurs )
        {
            String name = unConstructeur.getName();
            int m = unConstructeur.getModifiers() ;
            if ( Modifier.isPrivate(m) )
            {
                b = true ;
                if ( debug )
                    System.out.println( "hasSomePrivateConstructor" ) ;
            }
        }
        return b ;
    }
    //---------------------------------------------
    boolean hasSomePublicStaticDedicatedMethod ( Class _c )
    {
        boolean b = false ;
        Method [] publicMethods = _c.getMethods() ;
        for ( Method uneMethode : publicMethods )
        {
            String type = uneMethode.getReturnType().getName() ;
            int m = uneMethode.getModifiers() ;
            if (
                    ( Modifier.isPublic(m) )
                    && ( Modifier.isStatic(m) )
                    && ( _c.getName().compareTo(type) == 0 )
            )
            {
                b = true ;
                if ( debug )
                    System.out.println( "hasSomeDedicatedMethod" ) ;
            }
        }
        return b ;
    }
    //---------------------------------------------
    boolean hasSomePrivateStaticDedicatedProperty( Class _c )
    {
        boolean b = false ;
        Field [] tousChamps = _c.getDeclaredFields() ;
        for ( Field unAttribut : tousChamps )
        {
            int m = unAttribut.getModifiers() ;
            String type = unAttribut.getType().toString() ;
            type = type.replace("class ", "") ;
            //System.out.println( "type=" + type ) ;
            if (
                    (Modifier.isPrivate(m))
                    && (Modifier.isStatic(m))
                    && ( _c.getName().compareTo(type) == 0 )
            )
            {
                b = true ;
                if ( debug )
                    System.out.println( "hasSomeDedicatedProperty" ) ;
            }
        }
        return b ;
    }
    //---------------------------------------------
    void traiter ( String _className )
    {
        //System.out.println( "..." ) ;
        try
        {
            Class c = Class.forName(_className);

            if     (
                    hasNoPublicConstructor(c)
                    && hasSomePrivateConstructor(c)
                    && hasSomePublicStaticDedicatedMethod(c)
                    && hasSomePrivateStaticDedicatedProperty(c)
            )
            {
                System.out.println( "Singleton" ) ;
                System.out.println( " classe        : " + _className ) ;
            }
        }          
        catch (LinkageError ee)
        {
            System.out.println("pb pour traiter : " + _className );
        }
        catch (ClassNotFoundException e)
        {
            System.out.println("pb pour traiter : " + _className );
        }
    }
    //---------------------------------------------
}

Cas déjà traités

  • Singleton
  • Proxy ( avec variantes )
  • Observateur

Pour approfondir le sujet

jeudi 16 septembre 2010

Comment récupérer les types Jdbc et leurs libellés correspondants ?

Objectif

ne plus coder en dur dans des programmes des tableaux correspondants aux types Jdbc à traiter, mais les récupérer directement depuis la classe "java.sql.Types"

Solution

import java.lang.reflect.Field;
import java.util.Hashtable;

public class GetJdbcTypes
{
// ---------------------------------------------
Hashtable<Integer,String> lesTypes = new Hashtable<Integer,String>() ;
// ---------------------------------------------
public GetJdbcTypes() throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
Class c = Class.forName("java.sql.Types");
Field[] f = c.getFields();
for(int i=0;i<f.length;++i)
{
String lib = f[i].getName() ;
Integer ii = (Integer) f[i].get(c) ;
lesTypes.put(ii, lib) ;
System.out.println( lib + " = " + ii ) ;
}
}
// ---------------------------------------------
public static void main(java.lang.String[] args)
{
try
{
GetJdbcTypes appli = new GetJdbcTypes() ;
System.out.println( "nb = " + appli.lesTypes.size() ) ;
}
catch(Exception e)
{
e.printStackTrace();
}
}
// ---------------------------------------------
}

Résultat généré

BIT = -7
TINYINT = -6
...
NCLOB = 2011
SQLXML = 2009
nb = 36

Commentaires

  • le nombre de valeurs dépend de la version java, une vingtaine en jdk 1.4, 36 en jdk 6.
  • la classe ne contient que des entiers, pas besoin de complexifier ce traitement simple.

Pour approfondir le sujet

mercredi 11 août 2010

Phylogénie graphique des Ammonites en java


Objectif

Afficher dans un JTree l’arborescence évolutive ( la phylogénie ) des ammonites avec des images afin de mieux visualiser cette taxonomie et déterminer des fossiles plus simplement.

Introduction

Collectionneurs variés, vous vous êtes souvent demandés comment représenter sous forme de graphe par exemple une taxonomie comme celle des ammonites pour pouvoir mieux déterminer vos pierres.
Voici un exemple de ce qui a été  rapidement faisable de faire à partir d’un tutorial de sun d’exploration de fichier, couplé à l’affichage d’images dans un JTree.
Les images sont à récupérer sur le web ou ailleurs et à placer dans des répertoires qui représentent la taxonomie ( classe / ordre / famille / genre / espèce par exemple ) comme l’indique le schéma ci-dessous.
Le tutorial a été simplifié en retirant le composant JSplitPane et en faisant afficher les images ( feuilles ou non ) présents dans les répertoires.

Autres outils de représentation

Il existe de nombreux outils conçus dans différents langages pour « visualiser » au sens large des arborescences hiérarchiques diverses. Cet outil n’est qu’un démonstrateur qui a l’avantage d’être très simplement mis en place et qui s’adapte à pas mal de situations.
D’autres formes de visualisations ( tableaux, graphes, structures rayonnantes, etc. ) sont aussi pertinentes dans leurs contextes pour peu que l’on puisse naviguer facilement dans les niveaux dans des arborescences complexes.
Cet outil doit être pertinent concernant les BOM ( nomenclatures ).

Schéma de l’arborescence sur disque dur

Diagramme de classe fourni par sun

 

( mon outil de rétro-conception UML ne fait pas encore d’aussi beaux diagrammes )

Copie d’écran 1

Copie d’écran 2

Pour approfondir les sujets

Un bon site français concernant les ammonites : http://www.ammonites.fr
Un autre site : http://jsdammonites.fr/