29. Wie man ein Plugin für JMeter schreibt

Einführung von Peter Lin

Bei mehr als einer Gelegenheit haben sich Benutzer darüber beschwert, dass die Entwicklerdokumentation von JMeter veraltet und nicht sehr nützlich ist. Um es Entwicklern einfacher zu machen, habe ich mich entschieden, ein einfaches Schritt-für-Schritt-Tutorial zu schreiben. Als ich das Mike gegenüber erwähnte, hatte er einige Ideen, was das Tutorial abdecken sollte.

Bevor wir in das Tutorial eintauchen, möchte ich sagen, dass das Schreiben eines Plugins nicht unbedingt einfach ist, selbst für jemanden mit mehreren Jahren Java-Erfahrung. Die erste Erweiterung, die ich für JMeter geschrieben habe, war ein einfaches Dienstprogramm zum Analysieren von HTTP-Zugriffsprotokollen und zum Erstellen von Anfragen im XML-Format. Es war nicht wirklich ein Plugin, da es ein eigenständiges Befehlszeilenprogramm war. Mein erstes richtiges Plugin für JMeter war der Webservice-Sampler. Ich arbeitete an einem .NET-Projekt und musste einen Webservice einem Stresstest unterziehen. Die meisten kommerziellen Tools zum Testen von .NET-Webservices sind ätzend und kosten zu viel. Anstatt mehrere hundert Dollar für ein lahmes Testtool oder ein paar tausend Dollar für ein gutes zu bezahlen, entschied ich, dass es einfacher und billiger ist, ein Plugin für JMeter zu schreiben.

Nach zwei Wochen Programmieren in meiner Freizeit hatte ich einen funktionierenden Prototypen mit dem Apache Soap-Treiber. Ich schickte es zurück an JMeter und Mike fragte mich, ob ich ein Committer sein möchte. Ich hatte in der Vergangenheit Patches zu Jakarta JSTL und Tomcat beigetragen, also betrachtete ich es als Ehre. Seitdem habe ich den Zugriffsprotokoll-Sampler, den Tomcat 5-Monitor und das Verteilungsdiagramm geschrieben. Seitdem hat Mike den Zugriffsprotokoll-Sampler enorm verbessert und viel nützlicher gemacht.

Einführung von Mike Stover

Eines meiner Hauptziele beim Entwerfen von JMeter war es, das Schreiben von Plugins zu vereinfachen, um so viele Funktionen von JMeter wie möglich zu verbessern. Ein Teil des Vorteils, Open Source zu sein, besteht darin, dass viele Leute möglicherweise ihre Bemühungen zur Verbesserung der Anwendung einsetzen könnten. Ich habe mich bewusst dafür entschieden, etwas Einfachheit im Code zu opfern, um das Schreiben von Plugins zu einer Lebensweise für einen JMeter-Entwickler zu machen.

Während einige Leute erfolgreich direkt in den Code eingegraben und Verbesserungen an JMeter vorgenommen haben, fehlte ein echtes Tutorial, wie man das macht. Ich habe vor langer Zeit versucht, eine Dokumentation darüber zu schreiben, aber die meisten Leute fanden es nicht nützlich. Hoffentlich wird dieser Versuch mit Peters Hilfe erfolgreicher sein.

29.1 Grundstruktur von JMeter

JMeter ist nach Protokollen und Funktionalität organisiert. Dies geschieht, damit Entwickler neue JAR-Dateien für ein einzelnes Protokoll erstellen können, ohne die gesamte Anwendung erstellen zu müssen. Wir werden später in diesem Tutorial auf die Details zum Erstellen von JMeter eingehen. Da die meisten JMeter-Entwickler Eclipse verwenden, verwendet der Artikel das Eclipse-Verzeichnis als Referenzpunkt.

Stammverzeichnis - /eclipse/workspace/apache-jmeter/

Die Ordner innerhalb von apache-jmeter

Behälter
enthält die .bat- und .sh- Dateien zum Starten von JMeter. Es enthält auch ApacheJMeter.jar und eine Eigenschaftendatei
bauen/dokumente
Verzeichnis enthält die JMeter-Dokumentationsdateien
Extras
ant bezogene zusätzliche Dateien
lib
enthält die erforderlichen JAR-Dateien für JMeter
lib/ext
enthält die Kern-JAR-Dateien für JMeter und die Protokolle
Quelle
enthält Unterverzeichnisse für jedes Protokoll und jede Komponente
src/*/test
Unit-Test-bezogenes Verzeichnis
xdocs
XML-Dateien zur Dokumentation. JMeter generiert seine Dokumentation aus XML.

Im Laufe des Lernprogramms wird eine Erklärung der Unterverzeichnisse bereitgestellt. Konzentrieren wir uns zunächst auf das src- Verzeichnis.

Die Ordner innerhalb von src

bshclient
Code für den BeanShell-basierten Client
Bolzen
Code für das Bolt-Protokoll
Komponenten
enthält nicht protokollspezifische Komponenten wie Visualizer, Assertions usw.
Ader
der Kerncode von JMeter einschließlich aller Kernschnittstellen und abstrakten Klassen.
Abstand
erstellt ein Skript, das eine Verteilung erstellt
Dist-Check
Code zum Testen der Distribution. Es ist der Ort, an dem Sie suchen müssen, wenn Sie den Inhalt des resultierenden Quell-/Binärarchivs aktualisieren möchten
Beispiele
Beispiel-Sampler, der die Verwendung des neuen Bean-Frameworks demonstriert
Funktionen
Standardfunktionen, die von allen Komponenten verwendet werden
Generator
Code, um einen Testplan mit allen Elementen zu generieren. Wird zum Testen der Distribution verwendet
jorphan
Hilfsklassen, die allgemeine Hilfsfunktionen bereitstellen
Startprogramm
Code zum Starten und Stoppen von JMeter über die API
Lizenzen
enthält Informationen zu den in JMeters-Abhängigkeiten verwendeten Lizenzen
Protokoll
enthält die verschiedenen Protokolle, die JMeter unterstützt
Veröffentlichung
Code im Zusammenhang mit der Veröffentlichung der JMeter-Distribution
Testgerät
Dienstprogrammcode zum Testen
testkit-wiremock
Dienstprogrammcode zum Testen mit WireMock

Innerhalb des Protokollverzeichnisses befinden sich die protokollspezifischen Komponenten.

Die Ordner innerhalb des Protokolls

ftp
Komponenten für Belastungstests von FTP-Servern
http
Komponenten für Lasttests von Webservern
Java
Komponenten für Lasttests Java-Komponenten
jdbc
Komponenten für Belastungstests von Datenbankservern mit JDBC
jms
Komponenten für Belastungstests von JMS-Servern
junit
Komponenten für Lasttests mit JUnit-Tests
Junit-Beispiel
Beispiele für JUnit-basierte Testimplementierungen
LDAP
Komponenten für Lasttests von LDAP-Servern
Post
Komponenten für Lasttests von Mailservern
einheimisch
Komponenten für Belastungstests von systemeigenen Befehlen
TCP
Komponenten für Lasttests von TCP-Diensten

In der Regel befinden sich alle HTTP-bezogenen Sampler im http- Verzeichnis. Die Ausnahme von der Regel ist der Tomcat5-Monitor. Es ist separat, da die Funktionalität des Monitors etwas anders ist als bei Belastungs- oder Funktionstests. Es kann eventuell neu organisiert werden, aber im Moment befindet es sich in einem eigenen Verzeichnis. In Bezug auf die Schwierigkeit ist das Schreiben von Visualizern wahrscheinlich eines der schwieriger zu schreibenden Plugins.

29.2 JMeter Gui – TestElement-Vertrag

Beim Schreiben einer JMeter-Komponente müssen Sie sich bestimmter Verträge bewusst sein – wie sich eine JMeter-Komponente verhalten soll, wenn sie in der JMeter-Umgebung ordnungsgemäß ausgeführt wird. Dieser Abschnitt beschreibt den Vertrag, den der GUI-Teil Ihrer Komponente erfüllen muss.

Der GUI-Code in JMeter ist strikt vom Testelement-Code getrennt. Wenn Sie also eine Komponente schreiben, gibt es eine Klasse für das Testelement und eine andere für die GUI-Präsentation. Die GUI-Präsentationsklasse ist in dem Sinne zustandslos, dass sie niemals an einer Referenz auf das Testelement hängen sollte (es gibt jedoch Ausnahmen davon).

Ein GUI-Element sollte die entsprechende bereitgestellte abstrakte Klasse erweitern:

  • AbstractSamplerGui
  • AbstractAssertionGui
  • AbstractConfigGui
  • AbstractControllerGui
  • AbstractPostProcessorGui
  • AbstractPreProcessorGui
  • AbstractVisualizer
  • AbstractTimerGui

Diese abstrakten Klassen nehmen Ihnen so viel Klempnerarbeit ab, dass es kaum eine Option ist, sie nicht zu erweitern und stattdessen die Schnittstellen direkt zu implementieren. Wenn Sie das dringende Bedürfnis haben, diese Klassen nicht zu verlängern, können Sie sich mir im IRC anschließen, wo ich Sie vom Gegenteil überzeugen kann :-).

Sie haben also die entsprechende GUI-Klasse erweitert, was bleibt noch zu tun? Folge diesen Schritten:

  1. Implementieren Sie getLabelResource()
    1. Diese Methode sollte den Namen der Ressource zurückgeben, die den Titel/Namen der Komponente darstellt. Die Ressource muss in die Datei messages.properties von JMeter eingetragen werden (und möglicherweise auch Übersetzungen).
  2. Erstellen Sie Ihre GUI. Welchen Stil Sie auch mögen, gestalten Sie Ihre GUI. Ihre Klasse erweitert letztendlich JPanel , daher muss sich Ihr Layout im eigenen ContentPane Ihrer Klasse befinden . Verbinden Sie GUI-Elemente nicht über Aktionen und Ereignisse mit Ihrer TestElement -Klasse. Lassen Sie das interne Modell von Swing so weit wie möglich an allen Daten hängen.
    1. Einige Standard-GUI-Sachen sollten allen JMeter-GUI-Komponenten hinzugefügt werden:
      1. Rufen Sie setBorder(makeBorder()) für Ihre Klasse auf. Dadurch erhält es die Standard-JMeter-Grenze
      2. Fügen Sie den Titelbereich über makeTitlePanel() hinzu . Normalerweise ist dies das erste, was zu Ihrer GUI hinzugefügt wird, und sollte in einem vertikalen Box-Layoutschema oder mit der VerticalLayout - Klasse von JMeter erfolgen. Hier ist ein Beispiel für eine init() -Methode:
        private void init() {
            setLayout (neues BorderLayout());
            setBorder(makeBorder());
            Boxbox = Box.createVerticalBox();
            box.add (makeTitlePanel());
            box.add (makeSourcePanel ());
            add(box,BorderLayout.NORTH);
            add(makeParameterPanel(),BorderLayout.CENTER);
        }
        
  3. Public void configure(TestElement el) implementieren
    1. Achten Sie darauf, super.configure(e) aufzurufen . Dadurch werden einige der Daten für Sie ausgefüllt, z. B. der Name des Elements.
    2. Verwenden Sie diese Methode, um Daten in Ihre GUI-Elemente zu setzen. Beispiel:
      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. Implementieren Sie public void modifyTestElement(TestElement e) . Hier verschieben Sie die Daten von Ihren GUI-Elementen in das TestElement . Es ist die logische Umkehrung der vorherigen Methode.
      1. Rufen Sie super.configureTestElement(e) auf . Dadurch werden einige Standarddaten für Sie übernommen.
      2. Beispiel:
        public void modifyTestElement(TestElement e) {
            super.configureTestElement(e);
            e.setProperty(neue boolesche Eigenschaft(
                    RegexExtractor.USEHEADERS,
                    useHeaders.isSelected()));
            e.setProperty(RegexExtractor.MATCH_NUMBER,
                    matchNumberField.getText());
            if (e Instanz von RegexExtractor) {
                RegexExtractor regex = (RegexExtractor)e;
                regex.setRefName(refNameField.getText());
                regex.setRegex(regexField.getText());
                regex.setTemplate (templateField.getText());
                regex.setDefaultValue(defaultField.getText());
            }
        }
        
    4. Implementieren Sie das öffentliche TestElement createTestElement() . Diese Methode sollte eine neue Instanz Ihrer TestElement -Klasse erstellen und sie dann an die modifyTestElement(TestElement) -Methode übergeben, die Sie oben erstellt haben
      öffentliches Testelement createTestElement() {
          RegexExtractor-Extraktor = neuer RegexExtractor();
          ModifyTestElement (Extraktor);
          Rücksauger;
      }
      

Der Grund, warum Sie keine Referenz für Ihr Testelement festhalten können, liegt darin, dass JMeter Instanzen von GUI-Klassenobjekten für mehrere Testelemente wiederverwendet. Das spart viel Speicher. Es macht es auch unglaublich einfach, den GUI-Teil Ihrer neuen Komponente zu schreiben. Mit dem Layout in Swing muss man sich immer noch abmühen, aber man muss sich nicht darum kümmern, die richtigen Events und Aktionen zu erstellen, um die Daten aus den GUI-Elementen in das TestElement zu bekommen , wo es etwas Gutes bewirken kann. JMeter weiß, wann es Ihre configure- und modifyTestElement- Methoden aufrufen muss, wo Sie dies auf sehr einfache Weise tun können.

Das Schreiben von Visualizern ist jedoch ein Sonderfall.

29.3 Einen Visualizer schreiben

Da Lasttests im GUI-Modus eine schlechte Praxis sind, sollten Sie ein solches Plugin nicht entwickeln. Werfen Sie einen Blick auf aktuellere Komponenten wie:

Von den Komponententypen erfordern Visualizer eine größere Tiefe in Swing als so etwas wie Controller, Funktionen oder Sampler. Die vollständige Quelle für das Verteilungsdiagramm finden Sie in components/org/apache/jmeter/visualizers/ . Der Verteilungsgraph-Visualizer ist in zwei Klassen unterteilt.

DistributionGraphVisualizer
Visualizer, den JMeter instanziiert
Verteilungsgraph
JComponent, die den eigentlichen Graphen zeichnet

Der einfachste Weg, einen Visualizer zu schreiben, ist folgender:

  1. Erweitern Sie org.apache.jmeter.visualizers.gui.AbstractVisualizer
  2. Implementieren Sie alle zusätzlichen Schnittstellen, die für Rückrufe und Ereignisbenachrichtigungen benötigt werden. Beispielsweise implementiert der DistributionGraphVisualizer die folgenden Schnittstellen:
    • ImageVisualizer
    • ItemListener – laut den Kommentaren in der Klasse ist ItemListener veraltet und wird nicht mehr verwendet.
    • GraphListener
    • Löschbar

AbstractVisualizer bietet einige allgemeine Funktionen, die von den meisten Visualizern wie Graph Results verwendet werden. Die allgemeine Funktionalität, die von der abstrakten Klasse bereitgestellt wird, umfasst:

  • Testelemente konfigurieren – Dies bedeutet, dass ein neuer ResultCollector erstellt , die Datei festgelegt und das Fehlerprotokoll festgelegt wird
  • Erstellen Sie das Vorratsmenü
  • Aktualisieren Sie das Testelement, wenn Änderungen vorgenommen werden
  • Erstellen Sie einen Dateibereich für die Protokolldatei
  • Erstellen Sie das Titelfeld

In einigen Fällen möchten Sie möglicherweise das Menü für das Dateitextfeld nicht anzeigen. In diesem Fall können Sie die Methode init() überschreiben. Hier ist die Implementierung für DistributionGraphVisualizer .

/**
 * Initialisieren Sie die GUI.
 */
private void init() {
    this.setLayout (neues BorderLayout());

    // HAUPTFELD
    Randrand = new EmptyBorder(10, 10, 5, 10);
    this.setBorder (Rand);

    // Richten Sie das Diagramm mit Kopfzeile, Fußzeile, Y-Achse und Diagrammanzeige ein
    JPanel graphPanel = new JPanel (new BorderLayout());
    graphPanel.add (createGraphPanel(), BorderLayout.CENTER);
    graphPanel.add (createGraphInfoPanel(), BorderLayout.SOUTH);

    // Fügen Sie das Hauptpanel und das Diagramm hinzu
    this.add (makeTitlePanel(), BorderLayout.NORTH);
    this.add (graphPanel, BorderLayout.CENTER);
}

Als Erstes erstellt die Methode init ein neues BorderLayout . Je nachdem, wie Sie die Widgets gestalten möchten, möchten Sie möglicherweise einen anderen Layout-Manager verwenden. Denken Sie daran, dass die Verwendung verschiedener Layout-Manager etwas für Experten ist.

Als Zweites erstellt die Methode init einen Rahmen. Wenn Sie den Rahmen vergrößern oder verkleinern möchten, ändern Sie die vier ganzzahligen Werte. Jeder ganzzahlige Wert repräsentiert Pixel. Wenn Sie möchten, dass Ihr Visualizer keinen Rahmen hat, überspringen Sie die Zeilen 8 und 9. Zeile 13 ruft createGraphPanel auf, das für die Konfiguration und das Hinzufügen des DistributionGraph zum Visualizer verantwortlich ist.

private Komponente createGraphPanel() {
    graphPanel = neues JPanel();
    graphPanel.setBorder(BorderFactory.createBevelBorder(
    BevelBorder.LOWERED,Color.lightGray,Color.darkGray));
    graphPanel.add (Graph);
    graphPanel.setBackground (Color.white);
    graphPanel zurückgeben;
}

In Zeile 5 wird die Diagrammkomponente dem Diagrammfeld hinzugefügt. Im Konstruktor wird eine neue Instanz von DistributionGraph erstellt.

public DistributionGraphVisualizer() {
    model = new SamplingStatCalculator("Verteilung");
    graph = new DistributionGraph(model);
    graph.setBackground (Color.white);
    drin();
}

Der Konstruktor von DistributionGraphVisualizer ist für die Erstellung des Modells und des Diagramms verantwortlich. Jedes Mal, wenn ein neues Ergebnis vollständig ist, übergibt die Engine das Ergebnis an alle Listener, indem sie add(SampleResult res) aufruft . Der Visualizer übergibt das neue SampleResult an das Modell.

öffentlich synchronisiert void add(SampleResult res) {
    model.addSample(res);
    updateGui(model.getCurrentSample());
}

Im Fall von DistributionGraphVisualizer aktualisiert die Methode add das Diagramm nicht wirklich. Stattdessen ruft es updateGui in Zeile drei auf.

öffentliche synchronisierte void updateGui (Beispiele) {
    // Wir haben eine weitere Probe erhalten
    if (Verzögerung == Zähler) {
        updateGui();
        Zähler = 0;
    } anders {
        Zähler++;
    }
}

Im Gegensatz zu GraphVisualizer versucht das Verteilungsdiagramm zu zeigen, wie sich die Ergebnisse verklumpen; daher verzögert der DistributionGraphVisualizer die Aktualisierung. Die Standardverzögerung beträgt 10 Abtastergebnisse.

öffentlich synchronisiert void updateGui() {
    if (graph.getWidth() < 10) {
        graph.setPreferredSize(
                neue Dimension (getWidth() - 40,
                getHeight() - 160));
    }
    graphPanel.updateUI();
    graph.repaint();
}

Die Zeilen 2 bis 3 sollen die Größe des Diagramms ändern, wenn der Benutzer die Größe des Fensters ändert oder die Trennlinie zieht. Zeile 7 aktualisiert das Panel mit dem Graphen. Zeile 8 löst die Aktualisierung des DistributionGraph aus . Bevor wir uns mit dem Schreiben von Graphen befassen, gibt es ein paar wichtige Methoden, die Visualizer implementieren müssen.

öffentlicher String getLabelResource() {
    geben Sie "Verteilungsgrafiktitel" zurück;
}

Die Etikettenressource ruft den Namen der Schnellansicht aus der Eigenschaftendatei ab. Die Datei befindet sich in core/org/apache/jmeter/resources . Es empfiehlt sich, den Namen des Visualizers nicht fest zu codieren. Die Datei Message.properties ist alphabetisch organisiert, sodass das Hinzufügen eines neuen Eintrags einfach ist.

öffentlich synchronisiert void clear() {
    this.graph.clear();
    model.clear();
    neu streichen ();
}

Jede Komponente in JMeter sollte Logik für die Methode clear() implementieren. Andernfalls löscht die Komponente die Benutzeroberfläche oder das Modell nicht, wenn der Benutzer versucht, die letzten Ergebnisse zu löschen und einen neuen Test auszuführen. Wenn clear nicht implementiert ist, kann dies zu einem Speicherverlust führen.

öffentliche JComponent getPrintableComponent() {
    gib this.graphPanel zurück;
}

Die letzte Methode, die Visualizer implementieren sollten, ist getPrintableComponent() . Die Methode ist für die Rückgabe der JComponent verantwortlich, die gespeichert oder gedruckt werden kann. Diese Funktion wurde kürzlich hinzugefügt, damit Benutzer eine Bildschirmaufnahme eines beliebigen Visualizers speichern können.

29.4 GraphListener

Da Lasttests im GUI-Modus eine schlechte Praxis sind, sollten Sie ein solches Plugin nicht entwickeln. Werfen Sie einen Blick auf aktuellere Komponenten wie:

Visualisierer sollten GraphListener implementieren . Dies geschieht, um das Hinzufügen neuer Sample-Instanzen zu Listenern zu vereinfachen. Wenn das benutzerdefinierte Diagramm nicht jede einzelne Probe darstellt, muss die Schnittstelle in der Regel nicht implementiert werden.

öffentliche Schnittstelle GraphListener {
    public void updateGui (Beispiele);
    öffentlich void updateGui();
}

Die wichtige Methode in der Schnittstelle ist updateGui(Sample s) . Von DistributionGraphVisualizer sehen wir, dass es graph.repaint() aufruft , um das Diagramm zu aktualisieren. In den meisten Fällen sollte die Implementierung von updateGui(Sample s) genau das tun. ItemListenerVisualizer müssen diese Schnittstelle im Allgemeinen nicht implementieren. Die Schnittstelle wird mit Kombinationsfeldern, Kontrollkästchen und Listen verwendet. Wenn Ihre Schnellansicht eine davon verwendet und wissen muss, wann sie aktualisiert wurde, muss die Schnellansicht die Schnittstelle implementieren. Ein Beispiel für die Implementierung der Schnittstelle finden Sie unter GraphVisualizer .

29.5 Benutzerdefinierte Diagramme schreiben

Da Lasttests im GUI-Modus eine schlechte Praxis sind, sollten Sie ein solches Plugin nicht entwickeln. Werfen Sie einen Blick auf aktuellere Komponenten wie:

Für diejenigen, die neu bei Swing sind und noch keine benutzerdefinierten JComponents geschrieben haben, würde ich vorschlagen, sich ein Buch über Swing zu besorgen und ein gutes Gefühl dafür zu bekommen, wie Swing-Widgets funktionieren. Dieses Tutorial versucht nicht, grundlegende Swing-Konzepte zu erklären, und geht davon aus, dass der Leser bereits mit der Swing-API und dem MVC-Entwurfsmuster (Model View Controller) vertraut ist. Aus dem Konstruktor von DistributionGraphVisualizer sehen wir, dass eine neue Instanz von DistributionGraph mit einer Instanz des Modells erstellt wird.

public DistributionGraph (SamplingStatCalculator-Modell) {
    Dies();
    setModel (Modell);
}

Die Implementierung der setModel- Methode ist einfach.

private void setModel (Objektmodell) {
    this.model = (SamplingStatCalculator) Modell;
    neu streichen ();
}

Beachten Sie, dass die Methode repaint aufruft, nachdem sie das Modell festgelegt hat. Wenn repaint nicht aufgerufen wird, kann dies dazu führen, dass die GUI den Graphen nicht zeichnet. Sobald der Test beginnt, wird der Graph neu gezeichnet, daher ist das Aufrufen von repaint nicht kritisch.

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

Der andere wichtige Aspekt beim Aktualisieren des Widgets ist das Platzieren des Aufrufs von drawSample innerhalb eines synchronisierten Blocks. Wenn drawSample nicht synchronisiert wurde, löste JMeter zur Laufzeit eine ConcurrentModificationException aus. Je nach Testplan kann es ein Dutzend oder mehr Threads geben, die dem Modell Ergebnisse hinzufügen. Der synchronisierte Block wirkt sich nicht auf die Genauigkeit jeder einzelnen Anforderung und Zeitmessung aus, beeinträchtigt jedoch die Fähigkeit von JMeter, große Lasten zu generieren. Wenn die Anzahl der Threads in einem Testplan zunimmt, steigt die Wahrscheinlichkeit, dass ein Thread warten muss, bis der Graph mit dem Neuzeichnen fertig ist, bevor er eine neue Anforderung startet. Hier ist die Implementierung von drawSample .

private void drawSample(SamplingStatCalculator model, Graphics g) {
    Breite = getWidth ();
    doppelte Höhe = (double)getHeight() - 1,0;

    // Lassen Sie uns zuerst das Gitter zeichnen
    for (int y=0; y < 4; y++){
        int q1 = (int)(Höhe - (Höhe * 0,25 * y));
        g.setColor(Color.lightGray);
        g.drawLine(xborder,q1,width,q1);
        g.setColor (Farbe.schwarz);
        g.drawString(String.valueOf((25 * y) + "%"),0,q1);
    }
    g.setColor (Farbe.schwarz);
    // zeichne die X-Achse
    g.drawLine(xborder,(int)height,width,(int)height);
    // zeichne die Y-Achse
    g.drawLine(xborder,0,xborder,(int)height);
    // der Testplan muss mehr als 200 Samples haben
    // damit es eine halbwegs anständige Distribution generiert
    // Grafik. Je größer die Stichprobe, desto besser
    // Ergebnisse.
    if (model != null && model.getCount() > 50) {
        // Zeichnen Sie jetzt das Balkendiagramm
        Zahl neunzig = model.getPercentPoint(0.90);
        Zahl fünfzig = model.getPercentPoint(0.50);
        Gesamt = model.getCount();
        Sammlungswerte = model.getDistribution().values();
        Object[] objval = new Object[values.size()];
        objval = values.toArray(objval);
        // Wir sortieren die Objekte
        Arrays.sort (objval, neuer NumberComparator ());
        int len ​​= objval.length;
        for (int count=0; count < len; count++) {
            // Höhe berechnen
            Number[] num = (Number[])objval[count];
            double iper = (double)num[1].intValue() / (double)total;
            double iheight = Höhe * iper;
            // Wenn die Höhe kleiner als eins ist, setzen wir sie
            // zu einem Pixel
            if (iHöhe < 1) {
                iHöhe = 1,0;
            }
            int ix = (count * 4) + xborder + 5;
            int dhheight = (int)(height - iheight);
            g.setColor (Farbe.blau);
            g.drawLine(ix -1,(int)height,ix -1,dheight);
            g.drawLine(ix,(int)height,ix,dheight);
            g.setColor (Farbe.schwarz);
            // Zeichnen Sie eine rote Linie für den 90%-Punkt
            if (num[0].longValue() == ninety.longValue()) {
                g.setColor(Farbe.rot);
                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);
            }
            // Zeichne eine orangefarbene Linie für 50 % Punkt
            if (num[0].langerWert() == fünfzig.langerWert()) {
                g.setColor(Farbe.orange);
                g.drawLine(ix,(int)height,ix,30);
                g.drawString("50%",ix - 30,50);
                g.drawString(
                        String.valueOf(num[0].longValue()),
                        ix + 8, 50);
            }
        }
    }
}

Im Allgemeinen sollte das Rendern des Diagramms ziemlich schnell sein und keinen Engpass darstellen. Als allgemeine Regel ist es eine gute Idee, benutzerdefinierte Plugins zu profilieren. Die einzige Möglichkeit sicherzustellen, dass ein Visualizer kein Engpass ist, besteht darin, ihn mit einem Tool wie Borland OptimizeIt auszuführen. Eine gute Möglichkeit, ein Plugin zu testen, besteht darin, einen einfachen Testplan zu erstellen und ihn auszuführen. Das Heap- und Garbage-Collection-Verhalten sollte regelmäßig und vorhersehbar sein.

29.6 Erstellen eines TestBean-Plugins für JMeter

In diesem Teil werden wir den Prozess der Erstellung einer einfachen Komponente für JMeter durchlaufen, die das neue TestBean- Framework verwendet.

Diese Komponente wird ein Element zum Lesen von CSV-Dateien sein, mit dem Benutzer ihre Eingabedaten mithilfe von CSV-Dateien einfach ändern können. Um dieses Tutorial am effektivsten zu nutzen, öffnen Sie die drei unten angegebenen Dateien (im Verzeichnis src/components von JMeter ).

  1. Wählen Sie ein Paket aus und erstellen Sie drei Dateien:
    • [Komponentenname].java (org.apache.jmeter.config.CSVDataSet.java)
    • [Komponentenname]BeanInfo.java (org.apache.jmeter.config.CSVDataSetBeanInfo.java)
    • [Komponentenname]Resources.properties (org.apache.jmeter.config.CSVDataSetResources.properties)
  2. CSVDataSet.java muss die TestBean -Schnittstelle implementieren. Darüber hinaus wird es ConfigTestElement erweitern und LoopIterationListener implementieren .
    • TestBean ist eine Markierungsschnittstelle, daher müssen keine Methoden implementiert werden.
    • Das Erweitern von ConfigTestElement macht unsere Komponente zu einem Config -Element in einem Testplan. Indem Sie verschiedene abstrakte Klassen erweitern, können Sie den Elementtyp Ihrer Komponente steuern ( z. B. AbstractSampler , AbstractVisualizer , GenericController usw.). Sie können jedoch auch verschiedene Arten von Elementen erstellen, indem Sie einfach die richtigen Schnittstellen instanziieren. Die abstrakten Klassen können Ihr Leben verändern Einfacher).
  3. CSVDataSetBeanInfo.java sollte org.apache.jmeter.testbeans.BeanInfoSupport erweitern
    • Erstellen Sie einen Konstruktor mit Nullparametern, in dem wir super(CSVDataSet.class) aufrufen.
    • wir kommen darauf zurück.
  4. CSVDataSetResources.properties - vorerst leer
  5. Implementieren Sie Ihre spezielle Logik für Ihre Plugin-Klasse.
    1. Das CSVDataSet liest eine einzelne CSV-Datei und speichert die gefundenen Werte im laufenden Kontext von JMeter. Der Benutzer definiert die Datei, definiert die Variablennamen für jede „ Spalte “. Das CSVDataSet öffnet die Datei, wenn der Test beginnt, und schließt sie, wenn der Test endet (also implementieren wir TestListener ). Das CSVDataSet aktualisiert den Inhalt der Variablen für jeden Test-Thread und für jede Iteration durch seinen übergeordneten Controller, indem es neue Zeilen in der Datei liest. Wenn wir das Ende der Datei erreicht haben, fangen wir wieder am Anfang an. Beim Implementieren einer TestBean, achten Sie sorgfältig auf Ihre Eigenschaften. Diese Eigenschaften werden zur Grundlage eines GUI-Formulars, mit dem Benutzer das CSVDataSet- Element konfigurieren.
    2. Ihr Element wird von JMeter geklont, wenn der Test beginnt. Jeder Thread bekommt seine eigene Instanz. Sie haben jedoch die Möglichkeit zu steuern, wie das Klonen durchgeführt wird, wenn Sie dies benötigen.
    3. Eigenschaften: Dateiname , Variablennamen . Mit öffentlichen Gettern und Settern.
      • filename ist selbsterklärend, es enthält den Namen der CSV-Datei, die wir lesen werden
      • variableNames ist eine Zeichenfolge, die es einem Benutzer ermöglicht, die Namen der Variablen einzugeben, denen wir Werte zuweisen. Warum eine Schnur? Warum keine Sammlung? Sicherlich müssen Benutzer mehrere (und eine unbekannte Anzahl von) Variablennamen eingeben? Stimmt, aber wenn wir eine Liste oder Sammlung verwenden, müssten wir eine GUI-Komponente schreiben, um Sammlungen zu handhaben, und ich möchte das nur schnell erledigen. Stattdessen lassen wir Benutzer eine durch Kommas getrennte Liste von Variablennamen eingeben.
    4. Anschließend habe ich die IterationStart - Methode der LoopIterationListener -Schnittstelle implementiert. Der Punkt dieses "Ereignisses" besteht darin, dass Ihre Komponente benachrichtigt wird, wenn der Test in den übergeordneten Controller eingetreten ist. Für unsere Zwecke lesen wir jedes Mal, wenn der übergeordnete Controller von CSVDataSet aufgerufen wird, eine neue Zeile der Datendatei und setzen die Variablen. Somit führt bei einem normalen Controller jede Schleife durch den Test dazu, dass ein neuer Satz von Werten gelesen wird. Für einen Schleifencontroller wird jede Iteration dasselbe tun. Jeder Test-Thread erhält auch andere Werte.
  6. Einrichten Ihrer GUI-Elemente in CSVDataSetBeanInfo :
    • Sie können Gruppierungen für die Eigenschaften Ihrer Komponente erstellen. Jede Gruppierung, die Sie erstellen, benötigt eine Bezeichnung und eine Liste mit Eigenschaftsnamen, die in diese Gruppierung aufgenommen werden sollen. Dh:
      createPropertyGroup("csv_data",
              new String[] { "Dateiname", "Variablennamen" });
      
    • Erstellt eine Gruppierung namens csv_data , die GUI-Eingabeelemente für die Eigenschaften filename und variableNames von CSVDataSet enthält . Dann müssen wir definieren, welche Art von Eigenschaften diese sein sollen:
      p = Eigenschaft ("Dateiname");
      p.setValue(NOT_UNDEFINED, Boolean.TRUE);
      p.setValue (STANDARD, "");
      p.setValue(NOT_EXPRESSION, Boolean.TRUE);
      
      p = Eigenschaft ("Variablennamen");
      p.setValue(NOT_UNDEFINED, Boolean.TRUE);
      p.setValue (STANDARD, "");
      p.setValue(NOT_EXPRESSION, Boolean.TRUE);
      
      Dadurch werden im Wesentlichen zwei Eigenschaften erstellt, deren Wert nicht null sein darf und deren Standardwerte "" sind . Es gibt mehrere solcher Attribute, die für jede Eigenschaft festgelegt werden können. Hier ist ein Überblick:
      NICHT_UNDEFINIERT
      Die Eigenschaft wird nicht null gelassen .
      URSPRÜNGLICH
      Ein Standardwert muss angegeben werden, wenn NOT_UNDEFINED wahr ist .
      NICHT_AUSDRUCK
      Der Wert wird nicht für Funktionen analysiert, wenn dies wahr ist .
      NICHT_OTHER
      Dies ist kein Freiform-Eingabefeld – es muss eine Werteliste bereitgestellt werden.
      STICHWORTE
      Mit einem String[] als Wert wird eine vordefinierte Liste akzeptabler Werte erstellt, und JMeter erstellt eine Dropdown-Auswahl.
      Zusätzlich kann für eine Eigenschaft ein benutzerdefinierter Eigenschaftseditor angegeben werden:
      p.setPropertyEditorClass(FileEditor.class);
      
      Dadurch wird eine Texteingabe plus Schaltfläche zum Durchsuchen erstellt, die einen Dialog zum Suchen einer Datei öffnet. In der Regel sind keine komplexen Eigenschaftseinstellungen wie jetzt erforderlich. Ein komplexeres Beispiel finden Sie unter org.apache.jmeter.protocol.http.sampler.AccessLogSamplerBeanInfo
  7. Definieren Sie Ihre Ressourcenzeichenfolgen. In CSVDataSetResources.properties müssen wir alle unsere String-Ressourcen definieren. Um Übersetzungen bereitzustellen, würde man zusätzliche Dateien wie CSVDataSetResources_ja.properties und CSVDataSetResources_de.properties erstellen . Für unsere Komponente müssen wir die folgenden Ressourcen definieren:
    Anzeigename
    Dadurch wird ein Name für das Element bereitgestellt, das in Menüs angezeigt wird.
    csv_data.displayName
    Wir erstellen eine Eigenschaftsgruppierung namens csv_data , also müssen wir eine Bezeichnung für die Gruppierung bereitstellen
    Dateiname.displayName
    ein Label für das Eingabeelement filename.
    Dateiname.kurzeBeschreibung
    ein Tooltip-ähnlicher Hilfetext-Klappentext.
    variableNames.displayName
    ein Label für das Eingabeelement Variablenname.
    variableNames.shortDescription
    Tooltip für das Eingabeelement variableNames .
  8. Debuggen Sie Ihre Komponente.

29.6 Erstellen von JMeter

JMeter verwendet Gradle zum Kompilieren und Erstellen der Distribution. JMeter hat mehrere Aufgaben definiert, die es Entwicklern erleichtern, das vollständige Projekt zu erstellen. Für diejenigen, die mit Gradle nicht vertraut sind, es ist ein Build-Tool, das make unter Unix ähnelt. Eine Liste der Gradle-Aufgaben mit einer kurzen Beschreibung finden Sie in gradle.md , die sich im Stammverzeichnis der Quellen befindet.

Hier sind einige Beispielbefehle.

./gradlew runGui
Erstellen und starten Sie die JMeter-GUI
./gradlew createDist
Projekt erstellen und relevante JAR-Dateien in den Ordner ./lib kopieren
./gradlew :src:dist:previewSite
Erstellt eine Vorschau einer Site in ./build/docs/site
Go to top