JMeter — Criando testes de performance para o protocolo HTTP

Criando um script de teste básico

Lucas Gigek Carvalho
Editora Globo
7 min readNov 1, 2018

--

Antes de falarmos sobre o JMeter, acho que é importante dar um contexto básico sobre o que é teste de performance. Sendo muito generalista, o teste de performance tem como objetivo verificar como a aplicação se comporta quando ela é submetida a uma determinada carga. Dessa forma, conseguimos verificar se existe algum problema com a aplicação, com a hospedagem dela, ou com fatores externos à ela (como por exemplo uma modelagem não otimizada em um banco de dados que a aplicação de teste interage).

Existem vários tipos de teste de performance, que atendem objetivos específicos. Como o meu objetivo é falar um pouco sobre o JMeter, não vou me aprofundar nos tipos de teste.

Esse é o link para fazer o download da ferramenta. Para executá-la, precisamos da JVM instalada (link da documentação). Com a JVM configurada, é necessário executar o arquivo jmeter localizado no diretório bin. Esse é a interface do JMeter na versão mais recente (5.0):

JMeter 5.0

O JMeter é uma ferramenta de teste de performance que suporta várias aplicações e protocolos. Para o nosso caso (HTTP), ele faz requisições e retorna a resposta.

Até aí não é nada de mais, existem outras ferramentas (como o Insomnia ou Postman) que já fazem isso. A diferença do JMeter para essas outras ferramentas, é que ela fornece funcionalidades específicas para atender alguns conceitos existentes nos testes de performance, como think time, virtual users, ramp up, ramp down, etc.

Outra funcionalidade importante é que ela permite realizar requisições em sequencia lógica. Exemplificando, vamos supor que o sistema que queremos testar precisa que o usuário se autentique antes de fazer qualquer ação, então precisamos fazer uma requisição para ele se autenticar e depois a requisição para outra ação. Com o JMeter, podemos executar essas duas requisições. Com as ferramentas citadas a cima, é necessário fazer as duas requisições de forma manual.

Abrindo um rápido parenteses para explicar os conceitos listados anteriormente (think time, virtual users, ramp up e ramp down).

Dependendo da necessidade do teste, é necessário simular a interação entre usuário e aplicação da maneira mais fiel possível, o think time é uma “pausa” para o teste, onde ele vai esperar o tempo que foi especificado.

Exemplo de onde pode ser aplicado: em determinado fluxo, o usuário precisa preencher um formulário para prosseguir e, naturalmente, o usuário vai gastar alguns segundos para preencher os campos necessário. Nesse caso, podemos metrificar qual é o tempo médio que os usuários gastam, e aplicamos um think time nas requisições que dependem de alguma interação com o usuário.

Para definirmos quantas requisições serão feitas de forma simultânea no nosso teste, definimos esse valor como virtual users. É um conceito bem simples, e que em todos os testes são utilizados, então não vejo necessidade de exemplificar.

Dependendo do tipo de teste, é necessário que a quantidade de virtual users varie de acordo com o tempo. O processo de aumentar a quantidade de virtual users é chamado de ramp up, enquanto o processo de diminuir é chamado de ramp down.

Retirado de: https://qainsights.com/how-to-design-workload-model-for-load-testing/

Exemplo de onde pode ser aplicado: supondo que a necessidade do teste é saber até quantos usuários simultâneos a aplicação consegue atender sem apresentar falhas. Para esse caso, podemos começar o teste com uma quantidade definida de virtual users, e, com o passar do tempo, aumentamos esse número. Se a aplicação continuar respondendo sem problemas, podemos aumentar ainda mais esse número, até que os erros se apresentem e o limite seja definido.

Como exemplo, vou utilizar um repositório pessoal. Como a ideia é mostrar o funcionamento da ferramenta, o teste é algo muito simples, realizando apenas uma requisição GET para http://localhost:8080/actuator/health.

Antes de falar sobre os componentes e a estrutura do teste, é importante explicar que, para adicionar algo (um think time, uma validação, uma requisição HTTP, etc), é necessário clicar com o botão direto em um componente, “Add” e selecionar o componente desejado, de forma que cria-se uma estrutura de árvore. No exemplo a seguir, o componente Actuator Health, é responsável por fazer uma requisição HTTP, fazer uma validação com base no response code e fazer uma validação no JSON da resposta. Isso tudo porque ele possui componentes responsáveis por isso dentro dele. Veja na imagem a seguir:

Estrutura dos componentes do Actuator Health

Seguindo, a estrutura do nosso teste é a seguinte:

Estrutura dos componentes do test

Detalhando um pouco sobre cada componente:

Test Plan — responsável por agrupar todos componentes do teste. Dentro dele podemos definir variáveis para que o nosso teste use, mas nesse caso deixei as variáveis no User Defined Variables.

Test Plan

Thread Group — responsável pela configuração da execução, por exemplo, no campo Thread Properties podemos definir as configurações dos virtual users (quantidade de virtual users, tempo de ramp up), no campo Scheduler Configuration podemos definir as configurações referentes ao tempo de execução do teste. Como dito anteriormente, esse teste faz apenas uma requisição, sem se importar com a quantidade de tempo.

Thread Group

User Defined Variables — Responsável por criar variáveis que podem ser usadas durante o teste. Se, por exemplo precisarmos utilizar a variável url (ver exemplo a seguir), basta utilizar ${url}. Eu prefiro definir as variáveis em um User Defined Variables ao invés do Test Plan porque, se precisar trocar de ambiente, é só criar um novo User Defined Variables, definir os valores necessários e desabilitar o do ambiente que não será utilizado.

User Defined Variables

Na imagem a baixo, criei dois User Defined Variable, um para o ambiente de testes e um para o ambiente de produção (ambos fictícios), e deixei habilitado apenas para o ambiente de testes:

Once Only Controller — Serve para agrupar e organizar os componentes do nosso teste. Mais especificamente, organiza os dados da requisição e as validações que serão feitas na resposta dela

Once Only Controller

HTTP Request — É onde a requisição é efetuada. No nosso caso, definimos o protocolo, url, porta (todas configuradas no User Defined Variables), o método HTTP e a URI. Também podemos mandar parâmetros no header ou no body da requisição, mas como não é o nosso caso, o nosso exemplo não tem isso.

HTTP Request

Response Assertion — Tem o propósito de fazer verificações com base na resposta da requisição.

Existem diversos campos da respostas que podemos validar, mas no nosso caso, a validação que está sendo feita é em cima do campo Response Code, e se seu valor é 200. Caso essa validação esteja errada o teste falha.

Response Assertion

JSON Assertion — Tem o propósito de fazer verificações com base no JSON de resposta da requisição.

No nosso caso, estamos verificando se o campo status possui o valor UP. Caso essa validação esteja errada o teste falha.

JSON Assertion

View Result Tree — Tem como objetivo de mostrar as requisições que foram executadas durante o teste, detalhando os dados da requisição e também a sua resposta.

View Result Tree

Existem diversos componentes que não foram citados aqui, mas para um detalhamento completo sobre cada um, recomendo consultar a documentação do JMeter.

Apenas para ilustrar, no Thread Group aumentei para 10 virtual users, e executei o teste. Obtivemos o seguinte resultado:

Exemplo do teste que não houve nenhum erro na requisição/assertions

E agora, no JSON Assertion, troquei a validação de UP para DOWN, para exemplificar um caso de falha. Observe que no caso da falha da Assertion, o JMeter dá uma descrição detalhada do erro. Obtivemos o seguinte resultado:

Exemplo do teste que houve um erro no assertion

Espero que tenham gostado e aprendido alguma coisa. Caso tenham alguma dúvida ou queiram corrigir qualquer besteira que eu escrevi, é só me procurar.

Até a próxima =)

--

--