29. Comment écrire un plugin pour JMeter

Introduction de Peter Lin

À plus d'une occasion, les utilisateurs se sont plaints que la documentation du développeur de JMeter est obsolète et pas très utile. Afin de faciliter la tâche des développeurs, j'ai décidé d'écrire un didacticiel simple, étape par étape. Lorsque j'en ai parlé à Mike, il avait quelques idées sur ce que le tutoriel devrait couvrir.

Avant de plonger dans le tutoriel, j'aimerais dire que l'écriture d'un plugin n'est pas nécessairement facile, même pour quelqu'un qui a plusieurs années d'expérience en Java. La première extension que j'ai écrite pour JMeter était un utilitaire simple pour analyser les journaux d'accès HTTP et produire des requêtes au format XML. Ce n'était pas vraiment un plugin, car c'était un utilitaire de ligne de commande autonome. Mon premier vrai plugin pour JMeter était l'échantillonneur de service Web. Je travaillais sur un projet .NET et j'avais besoin de tester un service Web. La plupart des outils commerciaux disponibles pour tester les services Web .NET sont nuls et coûtent trop cher. Plutôt que de débourser plusieurs centaines de dollars pour un outil de test boiteux, ou quelques milliers de dollars pour un bon, j'ai décidé qu'il était plus facile et moins cher d'écrire un plugin pour JMeter.

Après deux semaines de codage sur mon temps libre, j'avais un prototype fonctionnel utilisant le pilote Apache Soap. Je l'ai renvoyé à JMeter et Mike m'a demandé si je voulais être un committer. J'avais contribué des correctifs à Jakarta JSTL et tomcat dans le passé, donc je considérais cela comme un honneur. Depuis lors, j'ai écrit l'échantillonneur de journal d'accès, le moniteur Tomcat 5 et le graphique de distribution. Depuis lors, Mike a considérablement amélioré l'échantillonneur de journal d'accès et l'a rendu beaucoup plus utile.

Présentation de Mike Stover

L'un de mes principaux objectifs lors de la conception de JMeter était de faciliter l'écriture de plugins pour améliorer autant de fonctionnalités de JMeter que possible. Une partie de l'avantage d'être open-source est que beaucoup de gens pourraient potentiellement prêter leurs efforts pour améliorer l'application. J'ai pris la décision consciente de sacrifier une certaine simplicité dans le code pour faire de l'écriture de plugins un mode de vie pour un développeur JMeter.

Alors que certaines personnes ont réussi à creuser directement dans le code et à apporter des améliorations à JMeter, un véritable tutoriel sur la façon de procéder fait défaut. J'ai essayé il y a longtemps d'écrire de la documentation à ce sujet, mais la plupart des gens ne l'ont pas trouvé utile. Espérons qu'avec l'aide de Peter, cette tentative sera plus fructueuse.

29.1 Structure de base de JMeter

JMeter est organisé par protocoles et fonctionnalités. Ceci est fait pour que les développeurs puissent créer de nouveaux jars pour un seul protocole sans avoir à créer l'intégralité de l'application. Nous entrerons dans les détails de la construction de JMeter plus tard dans le didacticiel. Étant donné que la plupart des développeurs JMeter utilisent eclipse, l'article utilisera le répertoire eclipse comme point de référence.

Répertoire racine - /eclipse/workspace/apache-jmeter/

Les dossiers à l'intérieur d' apache-jmeter

poubelle
contient les fichiers .bat et .sh pour démarrer JMeter. Il contient également ApacheJMeter.jar et le fichier de propriétés
build/docs
répertoire contient les fichiers de documentation JMeter
Suppléments
fichiers supplémentaires liés aux fourmis
bibliothèque
contient les fichiers jar requis pour JMeter
lib/ext
contient les fichiers jar de base pour JMeter et les protocoles
src
contient un sous-répertoire pour chaque protocole et composant
src/*/test
répertoire lié aux tests unitaires
xdocs
Fichiers XML pour la documentation. JMeter génère sa documentation à partir de XML.

Au fur et à mesure que le didacticiel progresse, une explication des sous-répertoires sera fournie. Pour l'instant, concentrons-nous sur le répertoire src .

Les dossiers à l'intérieur de src

bshclient
code pour le client basé sur BeanShell
verrouiller
code pour le protocole Bolt
Composants
contient des composants non spécifiques au protocole tels que des visualiseurs, des assertions, etc.
cœur
le code de base de JMeter, y compris toutes les interfaces de base et les classes abstraites.
distance
construit un script qui crée une distribution
dist-check
code lié au test de la distribution. C'est l'endroit à rechercher lorsque vous souhaitez mettre à jour le contenu de l'archive source/binaire résultante
exemples
exemple d'échantillonneur montrant comment utiliser le nouveau cadre de bean
les fonctions
fonctions standard utilisées par tous les composants
Générateur
code pour générer un plan de test avec tous les éléments. Utilisé pour tester la distribution
jorphan
classes utilitaires fournissant des fonctions utilitaires communes
lanceur
code pour aider à démarrer et arrêter JMeter via l'API
licences
contient des informations sur les licences utilisées dans les dépendances JMeters
protocole
contient les différents protocoles supportés par JMeter
Libération
code lié à la publication de la distribution JMeter
kit de test
code utilitaire pour les tests
testkit-wiremock
code utilitaire pour tester avec WireMock

Dans le répertoire de protocole , se trouvent les composants spécifiques au protocole.

Les dossiers à l'intérieur du protocole

ftp
composants pour tester la charge des serveurs ftp
http
composants pour les tests de charge des serveurs Web
Java
composants pour les tests de charge des composants java
jdbc
composants pour tester la charge des serveurs de base de données à l'aide de JDBC
jm
composants pour tester la charge des serveurs JMS
Junit
composants pour test de charge à l'aide de tests JUnit
junit-échantillon
exemples d'implémentations de test basées sur JUnit
LDAP
composants pour tester la charge des serveurs LDAP
courrier
composants pour tester la charge des serveurs de messagerie
originaire de
composants pour les tests de charge commandes natives du système d'exploitation
TCP
composants pour tester la charge des services TCP

En règle générale, tous les échantillonneurs liés à HTTP résideront dans le répertoire http . L'exception à la règle est le moniteur Tomcat5. Il est distinct, car la fonctionnalité du moniteur est légèrement différente de celle des tests d'effort ou fonctionnels. Il pourra éventuellement être réorganisé, mais pour l'instant il se trouve dans son propre répertoire. En termes de difficulté, écrire des visualiseurs est probablement l'un des plugins les plus difficiles à écrire.

29.2 JMeter Gui – Contrat TestElement

Lors de l'écriture d'un composant JMeter, vous devez connaître certains contrats - la manière dont un composant JMeter est censé se comporter s'il s'exécute correctement dans l'environnement JMeter. Cette section décrit le contrat que la partie GUI de votre composant doit respecter.

Le code GUI dans JMeter est strictement séparé du code Test Element. Par conséquent, lorsque vous écrivez un composant, il y aura une classe pour l'élément de test et une autre pour la présentation de l'interface graphique. La classe de présentation de l'interface graphique est sans état dans le sens où elle ne doit jamais s'accrocher à une référence à l'élément de test (il existe cependant des exceptions à cela).

Un élément GUI doit étendre la classe abstraite appropriée fournie :

  • RésuméSamplerGui
  • AbstraitAssertionGui
  • AbstractConfigGui
  • RésuméControllerGui
  • AbstractPostProcessorGui
  • AbstractPreProcessorGui
  • Visualiseur abstrait
  • AbstractTimerGui

Ces classes abstraites vous fournissent tellement de travail de plomberie que ne pas les étendre, et plutôt implémenter directement les interfaces n'est guère une option. Si vous avez un besoin impérieux de ne pas prolonger ces cours, alors vous pouvez me rejoindre sur IRC où je peux vous convaincre du contraire :-).

Donc, vous avez étendu la classe GUI appropriée, que reste-t-il à faire ? Suivez ces étapes:

  1. Implémenter getLabelResource()
    1. Cette méthode doit renvoyer le nom de la ressource qui représente le titre/nom du composant. La ressource devra être entrée dans le fichier messages.properties de JMeters (et éventuellement les traductions également).
  2. Créez votre interface graphique. Quel que soit le style que vous aimez, agencez votre interface graphique. Votre classe étend finalement JPanel , donc votre mise en page doit être dans le ContentPane de votre classe . N'associez pas d'éléments d'interface graphique à votre classe TestElement via des actions et des événements. Laissez le modèle interne de swing s'accrocher à toutes les données autant que possible.
    1. Certains éléments d'interface graphique standard doivent être ajoutés à tous les composants d'interface graphique JMeter :
      1. Appelez setBorder(makeBorder()) pour votre classe. Cela lui donnera la bordure JMeter standard
      2. Ajoutez le volet de titre via makeTitlePanel() . Il s'agit généralement de la première chose ajoutée à votre interface graphique et doit être effectuée dans un schéma de disposition verticale Box ou avec la classe VerticalLayout de JMeter . Voici un exemple de méthode init() :
        vide privé init() {
            setLayout(nouveau BorderLayout());
            setBorder(makeBorder());
            Boîte boîte = Boîte.createVerticalBox();
            box.add(makeTitlePanel());
            box.add(makeSourcePanel());
            add(box,BorderLayout.NORTH);
            add(makeParameterPanel(),BorderLayout.CENTER);
        }
        
  3. Implémenter public void configure(TestElement el)
    1. Assurez-vous d'appeler super.configure(e) . Cela remplira certaines des données pour vous, comme le nom de l'élément.
    2. Utilisez cette méthode pour définir des données dans vos éléments d'interface graphique. Exemple:
      public void configure(TestElement el) {
          super.configure(el);
          useHeaders.setSelected(
                  el.getPropertyAsBoolean(RegexExtractor.USEHEADERS));
          useBody.setSelected(
                  !el.getPropertyAsBoolean(RegexExtractor.USEHEADERS));
          regexField.setText(
                  el.getPropertyAsString(RegexExtractor.REGEX));
          templateField.setText(
                  el.getPropertyAsString(RegexExtractor.TEMPLATE));
          defaultField.setText(
                  el.getPropertyAsString(RegexExtractor.DEFAULT));
          matchNumberField.setText(
                  el.getPropertyAsString(RegexExtractor.MATCH_NUM));
          refNameField.setText(
                  el.getPropertyAsString(RegexExtractor.REFNAME));
      }
      
    3. Implémentez public void modifyTestElement(TestElement e) . C'est là que vous déplacez les données de vos éléments GUI vers le TestElement . C'est l'inverse logique de la méthode précédente.
      1. Appelez super.configureTestElement(e) . Cela prendra soin de certaines données par défaut pour vous.
      2. Exemple:
        public void modifyTestElement(TestElement e) {
            super.configureTestElement(e);
            e.setProperty(new BooleanProperty(
                    RegexExtractor.USEHEADERS,
                    useHeaders.isSelected()));
            e.setProperty(RegexExtractor.MATCH_NUMBER,
                    matchNumberField.getText());
            if (e instanceof RegexExtractor) {
                RegexExtractor regex = (RegexExtractor)e ;
                regex.setRefName(refNameField.getText());
                regex.setRegex(regexField.getText());
                regex.setTemplate(templateField.getText());
                regex.setDefaultValue(defaultField.getText());
            }
        }
        
    4. Implémentez public TestElement createTestElement() . Cette méthode doit créer une nouvelle instance de votre classe TestElement , puis la transmettre à la méthode modifyTestElement(TestElement) que vous avez créée ci-dessus
      public TestElement createTestElement() {
          Extracteur RegexExtractor = new RegexExtractor();
          modifyTestElement(extracteur);
          extracteur de retour;
      }
      

La raison pour laquelle vous ne pouvez pas conserver une référence pour votre élément de test est que JMeter réutilise une instance d'objets de classe GUI pour plusieurs éléments de test. Cela économise beaucoup de mémoire. Cela rend également incroyablement facile l'écriture de la partie graphique de votre nouveau composant. Vous devez toujours lutter avec la mise en page dans Swing, mais vous n'avez pas à vous soucier de créer les bons événements et actions pour obtenir les données des éléments de l'interface graphique dans le TestElement où cela peut faire du bien. JMeter sait quand appeler vos méthodes configure et modifyTestElement où vous pouvez le faire de manière très simple.

Cependant, l'écriture de visualiseurs est un cas particulier.

29.3 Écrire un visualiseur

Le test de charge en mode graphique étant une mauvaise pratique, vous ne devriez pas développer un tel plugin. Jetez un œil à des composants plus récents tels que :

Parmi les types de composants, les visualiseurs nécessitent une plus grande profondeur dans Swing que quelque chose comme les contrôleurs, les fonctions ou les échantillonneurs. Vous pouvez trouver la source complète du graphique de distribution dans components/org/apache/jmeter/visualizers/ . Le visualiseur de graphique de distribution est divisé en deux classes.

DistributionGraphVisualizerDistributionGraphVisualizer
visualiseur que JMeter instancie
DistributionGraph
JComponent qui dessine le graphe réel

La manière la plus simple d'écrire un visualiseur est de procéder comme suit :

  1. Étendre org.apache.jmeter.visualizers.gui.AbstractVisualizer
  2. Implémentez toutes les interfaces supplémentaires nécessaires pour le rappel et la notification d'événements. Par exemple, DistributionGraphVisualizer implémente les interfaces suivantes :
    • ImageVisualizer
    • ItemListener - selon les commentaires de la classe, ItemListener est obsolète et n'est plus utilisé.
    • GraphListener
    • Effacable

AbstractVisualizer fournit certaines fonctionnalités communes, que la plupart des visualiseurs comme Graph Results utilisent. La fonctionnalité commune fournie par la classe abstraite comprend :

  • Configurer les éléments de test - Cela signifie qu'il crée un nouveau ResultCollector , définit le fichier et définit le journal des erreurs
  • Créer le menu des stocks
  • Mettre à jour l'élément de test lorsque des modifications sont apportées
  • Créer un panneau de fichiers pour le fichier journal
  • Créer le panneau de titre

Dans certains cas, vous ne souhaiterez peut-être pas afficher le menu de la zone de texte du fichier. Dans ce cas, vous pouvez remplacer la méthode init() . Voici l'implémentation de DistributionGraphVisualizer .

/**
 * Initialiser l'interface graphique.
 */
vide privé init() {
    this.setLayout(new BorderLayout());

    // PANNEAU PRINCIPAL
    Marge de bordure = new EmptyBorder(10, 10, 5, 10);
    this.setBorder(marge);

    // Configurez le graphique avec l'en-tête, le pied de page, l'axe Y et l'affichage du graphique
    JPanel graphPanel = new JPanel(new BorderLayout());
    graphPanel.add(createGraphPanel(), BorderLayout.CENTER);
    graphPanel.add(createGraphInfoPanel(), BorderLayout.SOUTH);

    // Ajout du panneau principal et du graphique
    this.add(makeTitlePanel(), BorderLayout.NORTH);
    this.add(graphPanel, BorderLayout.CENTER);
}

La première chose que fait la méthode init est de créer un nouveau BorderLayout . Selon la façon dont vous souhaitez disposer les widgets, vous pouvez utiliser un gestionnaire de disposition différent. Gardez à l'esprit que l'utilisation de différents gestionnaires de mise en page est réservée aux experts.

La deuxième chose que fait la méthode init est de créer une bordure. Si vous souhaitez augmenter ou diminuer la bordure, modifiez les quatre valeurs entières. Chaque valeur entière représente des pixels. Si vous souhaitez que votre visualiseur n'ait pas de bordure, ignorez les lignes 8 et 9. La ligne 13 appelle createGraphPanel , qui est responsable de la configuration et de l'ajout du DistributionGraph au visualiseur.

Composant privé createGraphPanel() {
    graphPanel = new JPanel();
    graphPanel.setBorder(BorderFactory.createBevelBorder(
    BevelBorder.LOWERED, Color.lightGray, Color.darkGray));
    graphPanel.add(graphe);
    graphPanel.setBackground(Color.white);
    retourne graphPanel ;
}

À la ligne 5, le composant graphique est ajouté au panneau graphique. Le constructeur est l'endroit où une nouvelle instance de DistributionGraph est créée.

public DistributionGraphVisualizer() {
    model = new SamplingStatCalculator("Distribution");
    graph = new DistributionGraph(modèle);
    graph.setBackground(Color.white);
    init();
}

Le constructeur de DistributionGraphVisualizer est responsable de la création du modèle et du graphe. Chaque fois qu'un nouveau résultat est terminé, le moteur transmet le résultat à tous les écouteurs en appelant add(SampleResult res) . Le visualiseur transmet le nouveau SampleResult au modèle.

void synchronisé public add(SampleResult res) {
    model.addSample(res);
    updateGui(model.getCurrentSample());
}

Dans le cas de DistributionGraphVisualizer , la méthode add ne met pas réellement à jour le graphique. Au lieu de cela, il appelle updateGui à la ligne trois.

public synchronized void updateGui(Sample s) {
    // Nous avons reçu un autre échantillon
    si (délai == compteur) {
        updateGui();
        compteur = 0 ;
    } autre {
        compteur++ ;
    }
}

Contrairement à GraphVisualizer , le graphique de distribution tente de montrer comment les résultats s'agglutinent ; par conséquent, le DistributionGraphVisualizer retarde la mise à jour. Le délai par défaut est de 10 échantillons de résultats.

public synchronisé void updateGui() {
    si (graph.getWidth() < 10) {
        graph.setPreferredSize(
                nouvelle dimension(getWidth() - 40,
                getHeight() - 160));
    }
    graphPanel.updateUI();
    graph.repaint();
}

Les lignes 2 à 3 sont supposées redimensionner le graphique, si l'utilisateur redimensionne la fenêtre ou fait glisser le séparateur. La ligne 7 met à jour le panneau contenant le graphique. La ligne 8 déclenche la mise à jour du DistributionGraph . Avant de couvrir l'écriture de graphiques, il y a quelques méthodes importantes que le visualiseur doit implémenter.

chaîne publique getLabelResource() {
    renvoie "distribution_graph_title" ;
}

La ressource label récupère le nom du visualiseur à partir du fichier de propriétés. Le fichier se trouve dans core/org/apache/jmeter/resources . Il est préférable de ne pas coder en dur le nom du visualiseur. Le fichier Message.properties est organisé par ordre alphabétique, ce qui facilite l'ajout d'une nouvelle entrée.

public synchronisé void clear() {
    this.graph.clear();
    model.clear();
    repeindre();
}

Chaque composant de JMeter doit implémenter la logique de la méthode clear() . Si cela n'est pas fait, le composant n'effacera pas l'interface utilisateur ou le modèle lorsque l'utilisateur essaiera d'effacer les derniers résultats et d'exécuter un nouveau test. Si clear n'est pas implémenté, cela peut entraîner une fuite de mémoire.

public JComponent getPrintableComponent() {
    retourne this.graphPanel ;
}

La dernière méthode que les visualiseurs doivent implémenter est getPrintableComponent() . La méthode est chargée de renvoyer le JComponent qui peut être enregistré ou imprimé. Cette fonctionnalité a été récemment ajoutée afin que les utilisateurs puissent enregistrer une capture d'écran de n'importe quel visualiseur donné.

29.4 GraphListener

Le test de charge en mode graphique étant une mauvaise pratique, vous ne devriez pas développer un tel plugin. Jetez un œil à des composants plus récents tels que :

Les visualiseurs doivent implémenter GraphListener . Ceci est fait pour simplifier l'ajout de nouvelles instances d'échantillons aux écouteurs. En règle générale, si le graphique personnalisé ne trace pas chaque échantillon, il n'a pas besoin d'implémenter l'interface.

interface publique GraphListener {
    public void updateGui(Sample s);
    public void updateGui();
}

La méthode importante dans l'interface est updateGui(Sample s) . De DistributionGraphVisualizer , nous voyons qu'il appelle graph.repaint() pour actualiser le graphique. Dans la plupart des cas, l'implémentation de updateGui(Sample s) devrait faire exactement cela. Les ItemListenerVisualizers n'ont généralement pas besoin d'implémenter cette interface. L'interface est utilisée avec des listes déroulantes, des cases à cocher et des listes. Si votre visualiseur utilise l'un de ces éléments et a besoin de savoir quand il a été mis à jour, le visualiseur devra implémenter l'interface. Pour un exemple d'implémentation de l'interface, veuillez consulter GraphVisualizer .

29.5 Écrire des graphiques personnalisés

Le test de charge en mode graphique étant une mauvaise pratique, vous ne devriez pas développer un tel plugin. Jetez un œil à des composants plus récents tels que :

Pour ceux qui découvrent Swing et qui n'ont pas encore écrit de JComponents personnalisés, je suggérerais de lire un livre sur Swing et d'avoir une bonne idée du fonctionnement des widgets Swing. Ce didacticiel ne tentera pas d'expliquer les concepts de base de Swing et suppose que le lecteur est déjà familiarisé avec l'API Swing et le modèle de conception MVC (Model View Controller). À partir du constructeur de DistributionGraphVisualizer , nous voyons qu'une nouvelle instance de DistributionGraph est créée avec une instance du modèle.

public DistributionGraph (modèle SamplingStatCalculator) {
    cette();
    setModel(modèle);
}

L'implémentation de la méthode setModel est simple.

setModel vide privé (modèle objet) {
    this.model = (SamplingStatCalculator) modèle ;
    repeindre();
}

Notez que la méthode appelle repaint après avoir défini le modèle. Si repaint n'est pas appelé, cela peut empêcher l'interface graphique de dessiner le graphique. Une fois le test démarré, le graphique se redessine, donc appeler repeindre n'est pas critique.

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    SamplingStatCalculator final m = this.model ;
    synchronisé (m) {
        drawSample(m, g);
    }
}

L'autre aspect important de la mise à jour du widget consiste à placer l'appel à drawSample dans un bloc synchronisé. Si drawSample n'était pas synchronisé, JMeter lèverait une ConcurrentModificationException au moment de l'exécution. Selon le plan de test, il peut y avoir une douzaine de threads ou plus ajoutant des résultats au modèle. Le bloc synchronisé n'affecte pas la précision de chaque demande individuelle et la mesure du temps, mais il affecte la capacité de JMeter à générer des charges importantes. À mesure que le nombre de threads dans un plan de test augmente, la probabilité qu'un thread doive attendre que le graphique ait fini de se redessiner avant de démarrer une nouvelle requête augmente. Voici l'implémentation de drawSample .

private void drawSample (modèle SamplingStatCalculator, Graphics g) {
    largeur = getWidth();
    double hauteur = (double)getHeight() - 1.0 ;

    // dessinons d'abord la grille
    pour (int y=0; y < 4; y++){
        int q1 = (int)(hauteur - (hauteur * 0,25 * y));
        g.setColor(Color.lightGray);
        g.drawLine(xborder,q1,width,q1);
        g.setColor(Color.black);
        g.drawString(String.valueOf((25 * y) + "%"),0,q1);
    }
    g.setColor(Color.black);
    // dessine l'axe X
    g.drawLine(xborder,(int)height,width,(int)height);
    // dessine l'axe Y
    g.drawLine(xborder,0,xborder,(int)height);
    // le plan de test doit avoir plus de 200 échantillons
    // pour qu'il génère une distribution décente à mi-chemin
    // graphique. Plus l'échantillon est grand, meilleure est la
    // résultats.
    si (modèle != null && modèle.getCount() > 50) {
        // dessine maintenant le graphique à barres
        Nombre quatre-vingt-dix = model.getPercentPoint(0.90);
        Numéro cinquante = model.getPercentPoint(0.50);
        total = modèle.getCount();
        Valeurs de collection = model.getDistribution().values();
        Object[] objval = new Object[values.size()] ;
        objval = values.toArray(objval);
        // on trie les objets
        Arrays.sort(objval,new NumberComparator());
        int len ​​= objval.longueur ;
        for (int count=0; count < len; count++) {
            // calcule la hauteur
            Nombre[] num = (Nombre[])objval[nombre] ;
            double iper = (double)num[1].intValue() / (double)total ;
            double iheight = hauteur * iper ;
            // si la hauteur est inférieure à un, nous la définissons
            // à un pixel
            si (ihauteur < 1) {
                ihauteur = 1.0 ;
            }
            int ix = (count * 4) + xborder + 5 ;
            int dheight = (int)(hauteur - iheight);
            g.setColor(Color.blue);
            g.drawLine(ix -1,(int)height,ix -1,height);
            g.drawLine(ix,(int)height,ix,height);
            g.setColor(Color.black);
            // dessine une ligne rouge pour 90% point
            if (num[0].longValue() == quatre-vingt-dix.longValue()) {
                g.setColor(Color.red);
                g.drawLine(ix,(int)height,ix,55);
                g. drawLine(ix,(int)35,ix,0);
                g.drawString("90%",ix - 30,20);
                g. drawString(
                        String.valueOf(num[0].longValue()),
                        ix + 8, 20);
            }
            // dessine une ligne orange pour 50% point
            si (num[0].longValue() == cinquante.longValue()) {
                g.setColor(Color.orange);
                g.drawLine(ix,(int)height,ix,30);
                g.drawString("50%",ix - 30,50);
                g. drawString(
                        String.valueOf(num[0].longValue()),
                        ix + 8, 50);
            }
        }
    }
}

En général, le rendu du graphique devrait être assez rapide et ne devrait pas être un goulot d'étranglement. En règle générale, c'est une bonne idée de profiler les plugins personnalisés. La seule façon de s'assurer qu'un visualiseur n'est pas un goulot d'étranglement est de l'exécuter avec un outil comme Borland OptimizeIt. Un bon moyen de tester un plugin est de créer un plan de test simple et de l'exécuter. Le comportement du tas et de la récupération de place doit être régulier et prévisible.

29.6 Création d'un plugin TestBean pour JMeter

Dans cette partie, nous allons passer par le processus de création d'un composant simple pour JMeter qui utilise le nouveau framework TestBean .

Ce composant sera un élément de lecture de fichier CSV qui permettra aux utilisateurs de varier facilement leurs données d'entrée à l'aide de fichiers CSV. Pour utiliser plus efficacement ce didacticiel, ouvrez les trois fichiers spécifiés ci-dessous (qui se trouvent dans le répertoire src/components de JMeter ).

  1. Choisissez un package et créez trois fichiers :
    • [ComponentName].java (org.apache.jmeter.config.CSVDataSet.java)
    • [ComponentName]BeanInfo.java (org.apache.jmeter.config.CSVDataSetBeanInfo.java)
    • [ComponentName]Resources.properties (org.apache.jmeter.config.CSVDataSetResources.properties)
  2. CSVDataSet.java doit implémenter l' interface TestBean . De plus, il étendra ConfigTestElement et implémentera LoopIterationListener .
    • TestBean est une interface de marqueur, il n'y a donc aucune méthode à implémenter.
    • L'extension de ConfigTestElement fera de notre composant un élément Config dans un plan de test. En étendant différentes classes abstraites, vous pouvez contrôler le type d'élément de votre composant (c'est-à-dire AbstractSampler , AbstractVisualizer , GenericController , etc. - bien que vous puissiez également créer différents types d'éléments simplement en instanciant les bonnes interfaces, les classes abstraites peuvent rendre votre vie Plus facile).
  3. CSVDataSetBeanInfo.java doit étendre org.apache.jmeter.testbeans.BeanInfoSupport
    • créer un constructeur à paramètre zéro dans lequel nous appelons super(CSVDataSet.class);
    • nous y reviendrons.
  4. CSVDataSetResources.properties - vide pour l'instant
  5. Implémentez votre logique spéciale pour votre classe de plugin.
    1. Le CSVDataSet lira un seul fichier CSV et stockera les valeurs qu'il trouve dans le contexte d'exécution de JMeter. L'utilisateur définira le fichier, définira les noms des variables pour chaque " colonne ". Le CSVDataSet ouvrira le fichier au démarrage du test et le fermera à la fin du test (ainsi, nous implémentons TestListener ). Le CSVDataSet mettra à jour le contenu des variables pour chaque thread de test et pour chaque itération via son contrôleur parent, en lisant de nouvelles lignes dans le fichier. Lorsque nous arrivons à la fin du fichier, nous recommencerons au début. Lors de l'implémentation d'un TestBean, portez une attention particulière à vos propriétés. Ces propriétés deviendront la base d'un formulaire GUI par lequel les utilisateurs configureront l' élément CSVDataSet .
    2. Votre élément sera cloné par JMeter au démarrage du test. Chaque thread aura sa propre instance. Cependant, vous aurez la possibilité de contrôler la façon dont le clonage est effectué, si vous en avez besoin.
    3. Propriétés : filename , variableNames . Avec des getters et des setters publics.
      • filename est explicite, il contiendra le nom du fichier CSV que nous lirons
      • variableNames est une chaîne qui permettra à un utilisateur d'entrer les noms des variables auxquelles nous attribuerons des valeurs. Pourquoi une chaîne ? Pourquoi pas une Collection ? Les utilisateurs devront sûrement saisir plusieurs noms de variables (et un nombre inconnu de) ? C'est vrai, mais si nous utilisions une liste ou une collection, nous aurions à écrire un composant graphique pour gérer les collections, et je veux juste le faire rapidement. Au lieu de cela, nous laisserons les utilisateurs saisir une liste de noms de variables délimitée par des virgules.
    4. J'ai ensuite implémenté la méthode IterationStart de l' interface LoopIterationListener . Le but de cet "événement" est que votre composant est averti lorsque le test est entré dans son contrôleur parent. Pour nos besoins, chaque fois que le contrôleur parent du CSVDataSet est entré, nous allons lire une nouvelle ligne du fichier de données et définir les variables. Ainsi, pour un contrôleur standard, chaque boucle du test entraînera la lecture d'un nouvel ensemble de valeurs. Pour un contrôleur de boucle, chaque itération fera de même. Chaque thread de test obtiendra également des valeurs différentes.
  6. Configuration de vos éléments d'interface graphique dans CSVDataSetBeanInfo :
    • Vous pouvez créer des regroupements pour les propriétés de votre composant. Chaque groupement que vous créez nécessite une étiquette et une liste de noms de propriétés à inclure dans ce groupement. C'est à dire:
      createPropertyGroup("csv_data",
              new String[] { "filename", "variableNames" });
      
    • Crée un regroupement appelé csv_data qui inclura des éléments d'entrée GUI pour les propriétés filename et variableNames de CSVDataSet . Ensuite, nous devons définir le type de propriétés que nous voulons :
      p = propriété("nom de fichier");
      p.setValue(NOT_UNDEFINED, Boolean.TRUE);
      p.setValue(DEFAULT, "");
      p.setValue(NOT_EXPRESSION, Boolean.TRUE);
      
      p = propriété("variableNames");
      p.setValue(NOT_UNDEFINED, Boolean.TRUE);
      p.setValue(DEFAULT, "");
      p.setValue(NOT_EXPRESSION, Boolean.TRUE);
      
      Cela crée essentiellement deux propriétés dont la valeur n'est pas autorisée à être null et dont les valeurs par défaut sont "" . Plusieurs attributs de ce type peuvent être définis pour chaque propriété. Voici un aperçu :
      NOT_UNDEFINED
      La propriété ne sera pas laissée null .
      DÉFAUT
      Une valeur par défaut doit être donnée si NOT_UNDEFINED est true .
      NOT_EXPRESSION
      La valeur ne sera pas analysée pour les fonctions si cela est vrai .
      NOT_OTHER
      Il ne s'agit pas d'un champ de saisie libre - une liste de valeurs doit être fournie.
      MOTS CLÉS
      Avec un String [] comme valeur, cela établit une liste prédéfinie de valeurs acceptables, et JMeter créera une sélection déroulante.
      De plus, un éditeur de propriété personnalisé peut être spécifié pour une propriété :
      p.setPropertyEditorClass(FileEditor.class);
      
      Cela créera une entrée de texte plus un bouton de navigation qui ouvre une boîte de dialogue pour rechercher un fichier. Habituellement, les paramètres de propriété complexes ne sont pas nécessaires, comme maintenant. Pour un exemple plus complexe, regardez org.apache.jmeter.protocol.http.sampler.AccessLogSamplerBeanInfo
  7. Définition de vos chaînes de ressources. Dans CSVDataSetResources.properties, nous devons définir toutes nos ressources de chaîne. Pour fournir des traductions, il faudrait créer des fichiers supplémentaires tels que CSVDataSetResources_ja.properties et CSVDataSetResources_de.properties . Pour notre composant, nous devons définir les ressources suivantes :
    Afficher un nom
    Cela fournira un nom à l'élément qui apparaîtra dans les menus.
    csv_data.displayName
    nous créons un groupe de propriétés appelé csv_data , nous devons donc fournir une étiquette pour le groupe
    filename.displayName
    une étiquette pour l'élément d'entrée du nom de fichier.
    filename.shortDescription
    un texte d'aide en forme d'info-bulle.
    variableNames.displayName
    une étiquette pour l'élément d'entrée de nom de variable.
    variableNames.shortDescription
    info-bulle pour l' élément d'entrée variableNames .
  8. Déboguez votre composant.

29.6 Construire JMeter

JMeter utilise Gradle pour compiler et construire la distribution. JMeter a plusieurs tâches définies, ce qui permet aux développeurs de créer plus facilement le projet complet. Pour ceux qui ne sont pas familiers avec Gradle, c'est un outil de build similaire à make sur Unix. Une liste des tâches Gradle avec une courte description est fournie dans gradle.md , qui se trouve dans le répertoire source racine.

Voici quelques exemples de commandes.

./gradlew runGui
Construire et démarrer l'interface graphique JMeter
./gradlew createDist
Générez le projet et copiez les fichiers jar pertinents dans le dossier ./lib
./gradlew :src:dist:previewSite
Crée un aperçu d'un site dans ./build/docs/site
Go to top