Destilando JMeter II: Vamos escrever testes!

Leituras recomendadas antes desse artigo: “Destilando JMeter I: Introdução e Conceitos” e “http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

Don’t be evil! Use o JMeter para o bem :]

Esse é o segundo post da série Destilando JMeter. Esse artigo foca nas principais dúvidas do dia a dia para quem está testando páginas. Serviços seguem outra linha em muitos casos, e será abordado em um futuro post.

Para esse post estou tentando algo novo, com a ideia de tornar o post mais iterativo e a ferramenta mais fácil de aprender (e de quebra de pegar uns exemplos prontos, é claro). Caso queira ter 100% de proveito, baixe o arquivo: JMeterExample.jmx compatível com JMeter 1,9+ (recomendo o 2.11) e o JMeter para acompanhar os exemplos. Caso queira um JMeter com todos os plugins, baixe esse “https://github.com/camiloribeiro/rake-jmeter/tree/master/jmeter

Eu criei um plano de teste de performance onde vamos habilitando cada um dos exemplos e ver eles funcionando. Assim você pode ler o exemplo, entender o conceito e experimentar na ferramenta, apenas habilitando e acompanhando no relatório e nos debugers espalhados pelo plano.

O objetivo dessa série é fomentar material prático, didático e completamente gratuito em português. Ajude-me a entender o que falta (comente, envie suas dúvidas e o seu feedback!), e juntos podemos construir um material que vai ajudar os novos QAs e developers a ter uma curva de aprendizado mais rápida e fácil em JMeter e teste de performance.

JMeter sem mouse

Embora o JMeter exija muito mais atenção e cuidado do que velocidade e produtividade, aprender os comandos de teclado podem (e vão) salvar muito o seu tempo quando estiver debugando. Para demonstrar isso, experimente o seguinte exemplo: Abra o menu File, clique no Save para salvar as novas mudanças. Agora clique no menu Run e clique no Clear All para limpar os relatórios. E agora clique novamente no menu Run e clique em Start. Todos esses cliques podem ser substituídos por Ctrl + SER (Save, Clear e Run).

Outros comandos interessantes: Enable/Disable: Muitas vezes você vai precisar testar o seu script sem um determinado elemento, grupo, condição etc. Para fazer isso de forma rápida, use Ctrl + T, tanto para habilitar, quanto para desabilitar. Stop Testing: Começou o teste sem querer ou já viu a quantidade de erros no listener e desconfia que tem algo errado? Pare o teste com Ctrl + .Duplicate Node: Precisa duplicar um elemento para testar alguma mudança sem perder o que já estava usando? Ctrl+Shift+C. (Atenção: Use git, mesmo que localmente. Já perdi meu jmx por corrupção de dados algumas vezes. Se não fosse o git teria algumas horas de trabalho ;) )

Quer mais shortcuts? -:> https://wiki.apache.org/jmeter/JMeterShortcuts

Aonde colocar os nodes?

Um node é qualquer elemento do JMeter. Como vimos no post “Destilando JMeter I: Introdução e Conceitos“, eles podem ser um thread group, um sampler, um listener, um timer, um config element entre outros. Só para relembrar, o funcionamento do node está diretamente relacionado com aonde ele está aninhado. Se um timer por exemplo, está aninhado em um sampler (é filho de um sampler), ele só vai ser ativado naquele sampler. Lembre-se que apesar disso, como ele executa uma pausa no teste, ele tem efeitos colaterais sobre o teste como um todo.

Criar um plano

Não confunda o plano de testes do JMeter, com algum documento que sua empresa ou cliente precisa ou com o planejamento/estratégia de testes de performance/carga/stress. Aqui vamos falar sobre o plano da ferramenta e como flexibilizá-lo para alcançar alguns dos objetivos de um planejamento. Caso tenha interesse sobre planejamento, pode conferir o nosso post sobre “12 Lições aprendidas em Testes de Performance Server Side” ou lendo algum livro sobre o planejamento. Nesse post vamos trabalhar somente os aspectos técnicos da ferramenta.

-Plano baseado em iterações

O plano em iterações é ideal para dois casos distintos. O primeiro e mais comum, é o caso de quem precisa testar uma quantidade limitada de requisições, não importa o tempo. Para ver esse exemplo funcionando, habilite o plano “Fixed number of requests example” e execute o teste observando o resultado.

Exemplo de plano de teste com número fixo de execuções e threads
Exemplo de plano de teste com número fixo de execuções e threads

O número de requests vai ser o número de iterações definido no campo “Loop” vezes o número de threads. O ramp-up só vai “amortecer” o início dos testes, mas não afeta o resultado final em número de requests. PS: Não se preocupe, estamos usando um “Dummy Sampler”, o que significa que estamos emulando requisições dentro do próprio JMeter.

O segundo modelo é o teste “eterno”. A configuração é a mesma, mas ao invés de informar o número de repetições. só informamos o número de threads e selecionamos a opção “Forever”. Esse teste é pouco falado. Eu uso ele por exemplo, para testar a estratégia de rolling-deployment, Blue-Green deploy e eventualmente loging, mas isso é um tópico a ser discutido em um futuro post :) Caso queira manter um teste de “maturidade” ou soak test por um período bem long, também pode selecionar essa opção.

-Plano baseado em tempo

Esse é o meu preferido por alguns motivos. O primeiro e mais obvio, você tem um timebox, ou seja, aconteça o que acontecer, o seu teste vai levar “X minutos/horas”. Assim você pode se programar. Outro fator interessante é a possibilidade de brincar com planos gráficos como exemplificado nas figuras do post anterior “Destilando JMeter I: Introdução e Conceitos“.

Para o próximo exercício, vamos voltar a desabilitar (ctrl + T) o plano “Fixed number of requests example” e vamos habilitar o plano “Load test schedule example”. Como já falamos desse plano, vamos brincar com outra coisa. Ignore o conteúdo por agora, vamos ver throughput controller mais a frente, também tem dummies dentro desse plano. Observe que no topo do plano, temos algumas opções:

Exemplo de plano com timebox definida
Exemplo de plano com timebox definida

Salve, limpe os relatórios e execute o teste observando as threads no topo a esquerda (nessa imagem e no JMeter), onde tem um “10/10″ seguido de um quadrado verde na imagem anterior. Observe com atenção. Você vai ver que as threads vão crescer de forma linear, se manter estáveis e desligar de uma forma linear (2/sec). Isso acontece porque o nosso plano diz que é esperado (ou mais provavelmente aceitável) ter erros nas respostas desse teste. Logo, caso ele encontre um erro, ele deve registrar esse erro caso existam listeners, e continuar o teste como se nada tivesse acontecido. Agora mude para cada uma das opções e observe os comportamentos diferentes.

Cada opção deve ser usada em um contexto. A opção “Start Next Thread Loop” por exemplo, deve ser usada para quem tem “uma pitada” de teste funcional, ou seja, dependência de resultados anteriores para os próximos elementos. Vamos ver mais a frente o caso do CSRF Token ou Authentication Token, onde vamos fazer um get para pegar o token e vamos usar o token para postar algum conteúdo.

Nesse exemplo, caso falhemos ao fazer o get, não queremos executar um post e aumentar o ruido do nosso teste em relação a falhas da aplicação. Ao invés disso, podemos ignorar a continuidade desse teste dessa thread, e voltar essa thread para o início da requisição, dessa forma ela pode tentar pegar o token de novo com o get e continuar o teste. Pare alguns minutos e mude algumas configurações agora. Se precisar depois, pode baixar o arquivo novamente. O importante agora é experimentar, olhando, principalmente, o thread counter no topo a direita e os relatórios

Once Only Controller

O Once Only Controller, no português “Controlador para Unica Vez” é um Controlador. Ele controla o fluxo de execução do teste, evitando que uma thread execute mais que uma vez um determinado request, ou grupo de requests. Mas aqui mora um perigo. Ele faz com que cada thread execute esse grupo uma vez, e não que o teste execute esse grupo uma unica vez. Para entender, Vamos experimentar um de cada vez e ver o resultado no relatório de Summary Report.

Once Only Controler X Throughput Controller
Once Only Controler X Throughput Controller

Novamente, não se preocupe com os requests. Habilite somente o primeiro exemplo “Example of Once Only Controller” e execute o nosso mantra (ctrl + SER). Observe o Summary Report. No final do teste, você vai notar que cada uma das dez threads do nosso teste, passou nesse request uma vez. Essa abordagem é interessante para casos onde temos que buscar algum valor em uma página para todos os testes subsequentes, e que esse valor não mude conforme novas execuções forem realizadas.

Agora, desabilite esse teste e habilite o “Thoughput Controller with unmarked per user”. Execute ctrl + SER e veja o novo resultado. No final do teste, vai observar, que não importa o número de threads, o teste sempre vai executar essa operação, ou esse grupo de operações, uma única vez. Essa abordagem pode ser usada quando temos que injetar dados por exemplo.

Ps: Mais a frente vamos observar que podemos usar mais de um thread group ao mesmo tempo, e que claro, podemos ter um thread group com uma thread responsável por realizar setup dos dados também. O objetivo aqui não é dar uma solução, mas ajudar iniciantes e intermediários a experimentar diferentes abordagens e componentes do JMeter.

PS: Caso esteja usando mais de um JMeter agente/slave (cluster) para executar testes de dois ou mais computadores, o exemplo “Example of Real Once Only Controller” vai executar um request para cada uma das máquinas. Então cuidado com inserções de dados. É sempre mais recomendável fazer esse tipo de operação com ferramentas próprias para isso, como Chef ou Puppet.

Trabalhar com Headers e meta informações

O protocolo que usamos para web é bem simples. Ele é composto por um HEADER (cabeçalho) e um BODY (corpo) em abos os sentidos. O Header possui meta informações sobre a requisição e sobre a resposta, enquanto o corpo possui o conteúdo trafegado.

O header é muito importante. Através dele definimos muitas informações importantes, como por exemplo o tipo de conteúdo do body (HTML, JSON, XML, etc). O HTTP é um protocolo sem estado, ou seja, cada requisição é única e não contem por exemplo uma sessão para manter o “usuário” ou os privilégios, por isso usamos também o HEADER para enviar informações de autenticação.

Exemplo de headers manager
Exemplo de headers manager

Trabalhar com o JMeter envolve conhecer muito de HTTP, por isso, caso não conheça os tipos de header, procure um livro ou material na internet mais aprofundados. Nesse tutorial vamos focar na ferramenta, mas eu recomendo uma leitura desse artigo (https://en.wikipedia.org/wiki/List_of_HTTP_header_fields) antes de continuar nessa sessão, já que vamos ver alguns exemplos bem simples. Vamos ver mais exemplos usando header mais a frente :)

Extraindo AuthTokens para variáveis

Authentication Tokens foram um mecanismo criado com dois objetivos. O primeiro e mais comum, é garantir que o usuário é o usurário, em caso de redes sociais e aplicativos que requerem logins. O segundo motivo é para evitar que maquinas de repetição (como o JMeter ou Selenium por exemplo), webspiders (modelo de ferramenta para procurar vulnerabilidade), crawlers (ferramentas para “baixar” conteúdo de forma automática) consigam navegar pelo site.

Claro que o mecanismo é falho, e o auth token não é a solução definitiva (e nem única!) para resolver esse problema. O Authentication Token é uma dificuldade a mais quando falamos de automatizar testes de performance. Eu já usei ferramentas que lidavam razoavelmente com isso, como o Visual Studio 2010, o Rational Performance Tester e o próprio JMeter, mas em nenhuma delas, e em nenhum dos casos, isso foi gerenciado pelo record and replay da ferramenta.

Isso acontece porque diferentes sistemas implementam a segurança e a autenticação de maneiras diferentes. Alguns enviam um token novo para cada post. Outros pedem valor criptografado com o payload em duas ou três camadas de criptografia. Ou seja, não existe uma maneira simples e definitiva de lida com isso. O que você deve fazer é conversar com o seu time e descobrir como funciona a autenticação do seu sistema.

Aqui vamos executar dois exemplos, o CSRF e o de criptografia (mais a frente). O primeiro nessa sessão, vamos simular o modelo usado pelo Rails, chamado de csrf token (usado para evitar o ataque conhecido como Cross-Site Request Forgery).

Para fazer isso usando o Regular expression extractor por exemplo, comente todos os demais nodes e ative o “Extracting and sending Authentication Token”. Observe que ele tem dois samplers, um Get e um Post (ambos dumy teste). Agora olhe o conteúdo do “response data” do primeiro request (get) conforme a imagem abaixo:

Exemplo de token dentro do HTML de uma página
Exemplo de token dentro do HTML de uma página

A imagem acima simula um request com o body contendo um token. Eu copiei esse snippet do meu Facebook autenticado, então é um exemplo relativamente real. Se observar agora, aninhado nesse request, existe um “Regular expression extractor”, onde definimos uma expressão regular para pegar esse valor (veja a figura abaixo):

Extração de token de dentro de um corpo do html
Extração de token de dentro de um corpo do html

No número 1 definimos de onde queremos pegar o HTML. Isso é importante porque em alguns casos temos sub-samples por conta de redirecionamentos por exemplo (Falaremos sobre isso mais tarde). O número 2 define de aonde vamos executar a expressão regular. Nesse caso, queremos pegar um token no corpo, mas em outros casos, podemos querer pegar uma URL no header, mais especificamente no header location. O número 3 é a definição do nome da variável onde vamos guardar esse valor. E por ultimo, temos a expressão regular e o template. Caso tenha mais interesse em expressões regulares leia “https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions“. Aqui vamos nos limitar ao básico, usando uma expressão regular não muito bonita, mas de fácil compreensão, focando no uso do JMeter e deixando essas especificidades técnicas de lado.

Feito, isso, o nosso segundo request, que é o nosso post, vai usar o “HTTP Header Manager” comentado anteriormente para enviar o Authorization Header. Um terceiro elemento (Debug Sampler) ainda não comentado, mas que vai ser abordado mais a frente está ali para nos ajudar a ver o conteúdo da variável. Se você executar o teste agora, e olhar no relatório “View Results in a Tree” qualquer um dos itens para “Debug Sampler“, vai ver que o valor da variável authToken que definimos é realmente o valor do token que extraímos (Pode ver isso também no body do nosso post request):

Resultado do Debug mostrando valor da variável no relatório
Resultado do Debug mostrando valor da variável no relatório

Lembre-se que esse é um exemplo básico, mas você pode usar essa estratégia para quase qualquer website usando os frameworks mais populares, como Rails pra Ruby, Django pra Python ou Dropwizard/Jersey pra Java. Entenda o mecanismo do seu framework ou time e drible ele nos seus testes de performance.

- Outros usos para variáveis

Variáveis podem ser usadas por uma infinidade de razões. Enviar um Header ou authentication token dinamicamente é um exemplo interessante, mas também podemos usar variáveis para guardar uma URL criada pelo teste (exemplo citado do Location header) entre outras. Use a criatividade e pense em como reusar as informações que a própria página te dá.

Criar asserssões

-Validando 404 e outros erros

Algumas vezes você vai querer validar erros. Sim! Testar não é só testar o que funciona, mas testar se os erros esperados se comportam como deveriam, inclusive que isso não impacta a performance.

Mas existe um problema muito sério. O JMeter, por padrão segue a convenção de que códigos 1XX são informacionais, 2XX sucesso, 3XX Redirecionamento, logo respondem como sucesso, enquanto 4XX são erros do cliente e 5XX erros do servidor. Nesse caso, ele levanta um erro automaticamente sempre que um request 401 é respondido pelo servidor. Para evitar isso devemos especificar explicitamente que esperamos aquele response code. O jeito mais fácil de fazer isso é usando uma asserção de resposta (Response Assertion).

Vá ate o nosso projeto e comente todos os testes, e deixe somente o teste “Validating 401, 404 and other errors” habilitado. Você vai observar que dentro dele, existe um outro elemento desabilitado que se chama “Expected 401 With error“, deixe-o desabilitado. O exemplo deve parecer com essa figura:

Exemplo de explicita asserção de código de erro experado
Exemplo de explicita asserção de código de erro experado

Agora execute o teste. Você vai ver que o nosso teste está verde, mesmo recebendo um 404. Isso aconteceu pela combinação de dois fatores:

1 – Nos definimos nesse assert que não nos importamos com o código retornado, marcado re roxo no canto direito da imagem. MUITO cuidado com isso. Se marcar essa opção, o JMeter não vai logar NENHUM código de erro desse request como erro. Cuidado com o falso positivo. Para ver isso quebrando, desmarque a opção e rode o teste de novo. Vai ver que mesmo passando na condição testada, o status ainda quebra o teste.

2 – O nosso teste está esperando um “Response Code equals to 404″ e recebeu um 404. Sempre que usar a opção citada anteriormente, de ignorar status, tenha certeza absoluta que está cobrindo as condições do teste. Para ter certeza você pode usar o debug sampler (vamos ver a frente), pode usar um Dummy teste retornando o que está esperando (como nesse exemplo) ou pode ainda ter mais de um assert, assim, além de validar o código do erro por exemplo, pode validar o o corpo ou algum header (“Content-Type: error” por exemplo).

Agora desabilite somente esse node “Expected 404” e habilite o “Expected 401 With error“. Execute e verá o erro que pegamos quando o status está ignorado, mas a condição não foi satisfeita, como mostrado na imagem abaixo:

Exemplo de erro em um assert de código de erro do JMeter
Exemplo de erro em um assert de código de erro do JMeter

Esse erro é bem parecido com o do JUnit ou Cucumber por exemplo. Pratique um pouco mais usando o Dummy teste. Mude o Dummy test para ter outros valores. Crie duas ou três asserções e veja como isso funcione. Explore e aprenda mais!

Settando variáveis e escrevendo java

O JMeter também permite que adicionemos novas variáveis a qualquer momento, bem como mudar o valor delas. No exemplo abaixo, vamos ver como fazer isso usando vars.put e também vamos executar um snippet de código em java. Essa é uma das vantágens do JMeter 2.11, já que ele permite ter melhor legibilidade do que as versões anteriores. Para acompanhar o exemplo, desabilite todos os demais testes e habilite somente o teste “Example using bean shell processor“. Observe que estamos usando dois componentes novos. Um “User defined variables“, onde podemos definir variáveis e valores padrão para elas, e um segundo elemento chamado Bean Shell Pre Processor.

O pré processor faz exatamente o contrário do pós processor. Ele executa antes de enviar o request, e nele podemos fazer várias coisas, como mudar valores de variáveis, executar comandos java, ler um banco de dados, etc. O exemplo abaixo mostra uma pequena rotina em java, importando e duas classes e executando uma operação para criptografar uma String antes de enviá-la no request:

Exemplo de bean shell preprocessor com snippet de código java
Exemplo de bean shell preprocessor com snippet de código java

No exempo acima, depois de executar o código java, usamos o vars.put(“nomeDaVariavel”, valorDaVariavel) para incluir o valor desejado. Lembre-se que se usar o pre-processor para isso, o valor vai ser setado antes de fazer o request em que ele está aninhado, caso use o pos-processor o valor será setado depois do request. Experimente mudar algumas coisas na operação. Tente incluir essa variável em um header de authentication por exemplo. Depois use alguma operação java para receber um valor e descriptografá-lo

BONUS! Postando vários dados diferentes de um arquivo CSV

Foi pedido por email para implementar também o post de valores vindos de um arquivo CSV. Aqui vai um exemplo bem simples de como fazer isso. Desabilite todos os outros nodes e habilite o node “Geting data from a CSV file“. Observe que temos um arquivo com três colunas na raiz do nosso projeto no github. Nesse arquivo podemos ter qualquer tipo de informação, como por exemplo os dados para cadastrar usuários, dados para injetar em um JSON ou mesmo para passar em uma querystring.

No JMeter temos que adicionar um “CSV Data Set Config“, e especificar os nomes das variáveis que vamos usar, como nos exemplo abaixo:

Adicionando um config file para buscar informações em um arquivo CSV
Adicionando um config file para buscar informações em um arquivo CSV

Com essa configuração, falamos para o jmeter para buscar esse arquivo representado pelo filename, setar as variaveis para cada uma das colunas (sem cabeçalho no arquivo!) e finalmente temos as opções de encerrar o teste no final do arquivo ou continuar voltando ao começo. No meu caso de exemplo, eu pedi que ele reciclar o arquivo, mas você pode mudar e ver como o teste acaba quando chegamos ao final do arquivo.

Para usar os valores basta incluílos basta usar o nosso padrão ${variavel} visto anteriormente:

Exemplo de envio e recebibento de variaveis do arquivo csv
Exemplo de envio e recebibento de variaveis do arquivo csv

O resultado como esperado pode ser visto usando os dummy tests que estamos usando desde o começo do tutorial:

Visualização dos dados vindos do arquivo csv depois da execução
Visualização dos dados vindos do arquivo csv depois da execução

Crie mais dados, experimente combinações diferentes. Tente usar outros config elements para buscar informações em bancos de dados também.

BONUS 2! Postando valores randômicos

O JMeter tem um conjunto gigante de funções prórias. Você pode ler e aprender mais sobre elas na definição da API do jmeter “https://jmeter.apache.org/usermanual/functions.html“. Caso seja necessário por exemplo, mudar algum valor no final de uma variável para que ele seja único você tem duas opções.

Usar a função ${__Random()}, ${__RandomString()} ou uma combinação delas com a ${__Random()}. Para testar isso, desabilite todos os outros testes e deixe somente o teste “Posting a unique string with random function“. Vai ver que as funções estão definidas de acordo com a imagem abaixo:

Três exemplos de funções randomicas para seus testes
Três exemplos de funções randomicas para seus testes

O resultado pode ser bem interessante, dependendo de qual charset você quer usar. No nosso caso não temos preferência por charset algum, então temos letras de várias línguas:

Resultado das funções randômicas
Resultado das funções randômicas

Experimente mudar as combinações, passar essas funções nos headers, final de urls, em cookies e aproveite para usar esses testes para definir testes de charsets também. Para mais consulte a documentação da Random (https://jmeter.apache.org/usermanual/functions.html#__Random), RandomString (https://jmeter.apache.org/usermanual/functions.html#__RandomString) e dateTime (https://jmeter.apache.org/usermanual/functions.html#__time)

O que achou desse novo post sobre JMeter? Espero que tenha gostado. compartilhe e vamos para o próximo level. Envie suas dúvidas aqui no comentário. Infelizmente não consigo responder todos os meus emails e acabo deixando alguns sem responder. Se estiver aqui no blog, alguém que também tenha trabalhado com JMeter pode ver e responder mais rápido.

Sinta-se a vontade para levar o material para sua empresa e usá-lo (inteiro ou parcial) em treinamentos ou quaisquer atividades não comerciais. Todo esse material é desenvolvido de forma voluntária. Você me ajude a continuar postando quando compartilha esse e outros posts no LinkedIn ou Twitter, ou mesmo mandando um e-mail para a lista de teste/desenvolvimento da sua empresa.

Muito obrigado e bons testes! :)

Camilo Ribeiro

Test Engineer at Klarna
Desenvolvedor, testador e agilista desde 2005, atualmente trabalhando na Suécia.

3 thoughts on “Destilando JMeter II: Vamos escrever testes!

  1. Hi Philippe,

    Thank you very much for the visit and compliment!
    I am sorry, but I don’t have a english version for this post :(
    Just to let you know, this is a introductory post about some “unknown” features from jmeter, and the Beanshell is one of those features. As the public target are mostly beginners, I choose to keep it simple in Java.
    But thank you for the information. I will update the post and add a note about the performance for groovy.

    Have a nice evening!

    Sincerely,

    Camilo

  2. Muito bom o post Camilo. Gostaria de saber se conheces alguma ferramenta para testes de performance em aplicativos mobile (android).
    Obrigada.

Leave a Reply