Pianificare i test di carico usando Apache JMeter

Completato

In questa sezione si analizzeranno i test di carico e si apprenderà come aggiungerli alla pipeline. I test di carico usano Apache JMeter per simulare più utenti che accedono all'app Web contemporaneamente. I test recuperano il contenuto Web dall'app eseguita nel Servizio app di Azure nell'ambiente di staging.

Tim inizia con l'introduzione dell'interfaccia utente di Apache JMeter su un portatile. Esegue un piano di test di base. Quindi, Tim e Mara esportano il piano di test in un file che può essere eseguito dalla riga di comando. Infine, aggiungono attività ad Azure Pipelines per eseguire i test di carico durante il processo di gestione temporanea.

Nota

Per ragioni di sintesi, non è necessario installare Apache JMeter nel computer locale. È possibile semplicemente leggere.

Eseguire test di carico da Apache JMeter

Apache JMeter è uno strumento di test di carico open source che analizza e misura le prestazioni. Il report generato è un file XML.

Azure Pipelines può leggere il report Apache JMeter e generare un grafico. Non è necessario alcun hardware speciale per eseguire questi test, quindi è possibile usare un agente ospitato da Microsoft per eseguirli. Nello scenario di Space Game è probabile che questi test vengano eseguiti nell'ambiente di gestione temporanea.

Creare il piano di test

Ecco l'aspetto di Apache JMeter in un portatile che esegue Linux:

Screenshot of the Apache JMeter user interface.

Creare un nuovo file del piano di test, ad esempio LoadTest.jmx. Aggiungere quindi un gruppo di thread al file. Ogni utente simulato viene eseguito nel proprio thread. Un gruppo di thread controlla il numero di utenti e il numero di richieste di ogni utente.

L'esempio seguente mostra 10 utenti simulati (thread). Ogni utente effettua 10 richieste, quindi il sistema ottiene un totale di 100 richieste.

Screenshot of specifying the thread group in Apache JMeter.

Un campionatore è una singola richiesta eseguita da JMeter. JMeter è in grado di eseguire query sui server tramite HTTP, FTP, TCP e diversi altri protocolli. I campionatori generano i risultati che vengono aggiunti al report.

Aggiungere quindi le impostazioni predefinite della richiesta HTTP e un campionatore di richiesta HTTP al gruppo di thread. Immettere il nome host del sito Web Space Game che viene eseguito nell'ambiente di gestione temporanea del Servizio app di Azure.

Screenshot that shows specifying the HTTP request in Apache JMeter.

Lo scenario precedente crea un piano di test di base.

Eseguire il piano di test

JMeter consente di eseguire molti tipi di test. È possibile eseguire il piano di test dall'interfaccia utente grafica di JMeter. Tuttavia, per i test di carico, la documentazione di JMeter consiglia di eseguire il piano di test dalla riga di comando.

Eseguire il piano di test usando questo comando:

apache-jmeter-5.4.1/bin/./jmeter -n -t LoadTest.jmx -o Results.xml

L'argomento -n specifica di eseguire JMeter in modalità non GUI. L'argomento -t specifica il file del piano di test LoadTest.jmx. L'argomento -o specifica il file di report Results.xml.

JMeter viene eseguito e produce il file di report Results.xml. Questo esempio di file mostra i primi risultati:

<?xml version="1.0" encoding="UTF-8"?>
<testResults version="1.2">
<httpSample t="180" it="0" lt="95" ct="35" ts="1569306009772" s="true" lb="HTTP Request" rc="200" rm="OK" tn="Thread Group 1-1" dt="text" by="40871" sby="144" ng="1" na="1">
  <java.net.URL>http://tailspin-space-game-web-staging-1234.azurewebsites.net/</java.net.URL>
</httpSample>
<httpSample t="174" it="0" lt="96" ct="38" ts="1569306009955" s="true" lb="HTTP Request" rc="200" rm="OK" tn="Thread Group 1-1" dt="text" by="40869" sby="144" ng="1" na="1">
  <java.net.URL>http://tailspin-space-game-web-staging-1234.azurewebsites.net/</java.net.URL>
</httpSample>
<httpSample t="160" it="0" lt="121" ct="35" ts="1569306010131" s="true" lb="HTTP Request" rc="200" rm="OK" tn="Thread Group 1-1" dt="text" by="40879" sby="144" ng="2" na="2">
  <java.net.URL>http://tailspin-space-game-web-staging-1234.azurewebsites.net/</java.net.URL>
</httpSample>

Ogni esempio produce un nodo nel report. L'attributo t specifica il tempo di risposta in millisecondi (ms). Qui vengono visualizzate tre richieste che hanno richiesto 180 ms, 174 ms e 160 ms.

I tempi di richiesta ideali devono essere in media inferiori a un secondo. Non più del 10% delle richieste deve richiedere più di un secondo. È possibile configurare JMeter per segnalare le statistiche, ad esempio i tempi di risposta minimi, massimi e medi o la deviazione standard. È possibile scrivere uno script per fornire queste informazioni.

Per visualizzare i risultati del test, è necessario specificarli in un formato comprensibile da Azure Pipelines. Azure Pipelines consente di analizzare un file XML che contiene i risultati del test, ma il file deve essere in un formato supportato. I formati supportati includono CTest, JUnit (incluso PHPUnit), NUnit 2, NUnit 3, Visual Studio Test (TRX) e xUnit 2. È possibile scrivere un file XSLT che converta i risultati di JMeter in JUnit.

Trasformare il report in JUnit

XSLT sta per Trasformazione XSL o Extensible Stylesheet Language Transformations. Un file XSLT è simile a un file XML, ma consente di trasformare un documento XML in un altro formato XML.

Ricordare i requisiti per i test di carico:

  • Il tempo medio di richiesta deve essere inferiore a un secondo.
  • Non più del 10% delle richieste deve richiedere più di un secondo.

Di seguito è riportato l'aspetto di un file XSLT che soddisfa tali requisiti:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:math="http://exslt.org/math">
  <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
  <xsl:template match="/testResults">
    <xsl:variable name="times" select="./httpSample/@t" />
    <xsl:variable name="failures" select="./httpSample/assertionResult/failureMessage" />
    <xsl:variable name="threshold" select="1000" />
    <testsuite>
      <xsl:attribute name="tests"><xsl:value-of select="count($times)" /></xsl:attribute>
      <xsl:attribute name="failures"><xsl:value-of select="count($failures)" /></xsl:attribute> 
      <testcase>
          <xsl:variable name="avg-time" select="sum($times) div count($times)" />
          <xsl:attribute name="name">Average Response Time</xsl:attribute>
          <xsl:attribute name="time"><xsl:value-of select="format-number($avg-time div 1000,'#.##')"/></xsl:attribute>
          <xsl:if test="$avg-time > $threshold">
            <failure>Average response time of <xsl:value-of select="format-number($avg-time,'#.##')"/> exceeds <xsl:value-of select="$threshold"/> ms threshold.</failure>
          </xsl:if> 
      </testcase>
      <testcase>
          <xsl:variable name="exceeds-threshold" select="count($times[. > $threshold])" />
          <xsl:attribute name="name">Max Response Time</xsl:attribute>
          <xsl:attribute name="time"><xsl:value-of select="math:max($times) div 1000"/></xsl:attribute>
          <xsl:if test="$exceeds-threshold > count($times) * 0.1">
            <failure><xsl:value-of select="format-number($exceeds-threshold div count($times) * 100,'#.##')"/>% of requests exceed <xsl:value-of select="$threshold"/> ms threshold.</failure>
          </xsl:if>
      </testcase>
    </testsuite>
  </xsl:template>
</xsl:stylesheet>

Non verrà approfondito il funzionamento di XSL in questa sezione. Tuttavia, per riepilogare, questo file raccoglie prima i dati seguenti dall'output di JMeter:

  • La durata di ogni richiesta HTTP.

    Raccoglie questi dati selezionando l'attributo t da ogni elemento httpSample. (./httpSample/@t)

  • Ogni messaggio di errore.

    Raccoglie questi dati selezionando tutti i nodi failureMessage dal documento. (./httpSample/assertionResult/failureMessage)

Il file XSLT imposta anche il valore soglia su 1.000 ms. Questo tempo di risposta rappresenta il valore massimo definito in precedenza.

Date queste variabili, il file XSLT presenta il numero totale di test e il numero totale di errori, per poi illustrare questi due test case:

  • Il tempo medio di risposta e un errore, se la media supera la soglia di 1.000 ms.
  • Il tempo massimo di risposta e un errore, se più del 10% delle richieste supera la soglia di 1.000 ms.

I risultati del file XSLT corrispondono al formato JUnit, che Azure Pipelines riconosce. È possibile denominare il file XSLT JMeter2JUnit.xsl.

A questo punto, è necessario un processore XSLT. In questo esempio si userà xsltproc, che è uno strumento da riga di comando per applicare fogli di stile XSLT ai documenti XML.

È possibile installare xsltproc come indicato di seguito:

sudo apt-get install xsltproc

Eseguire quindi xsltproc per trasformare il report JMeter in JUnit:

xsltproc JMeter2JUnit.xsl Results.xml > JUnit.xml

Ecco il file JUnit risultante, JUnit.xml:

<?xml version="1.0" encoding="UTF-8"?>
<testsuite xmlns:math="http://exslt.org/math" tests="100" failures="0">
  <testcase name="Average Response Time" time="0.17"/>
  <testcase name="Max Response Time" time="0.373"/>
</testsuite>

In questo esempio, il tempo medio di risposta è 170 ms. Il tempo di risposta massimo è 373 ms. Nessuno dei test case genera un errore perché entrambi i tempi sono inferiori alla soglia di 1.000 ms.

A breve verranno eseguiti questi test nella pipeline. È possibile considerare Results.xml, il file scritto da JMeter, come file intermedio che non viene pubblicato nei risultati del test della pipeline. JUnit.xml è il file di report finale. Questo file viene pubblicato nella pipeline in modo che il team possa visualizzare i risultati.