Przejdź do treści

Automatyczny think time w Gatlingu

Wstęp

Gatling to popularne narzędzie open-source do testów wydajnościowych aplikacji webowych i REST API. Pozwala tworzyć testy, które symulują ruch użytkowników w aplikacji. Wysyła żądania HTTP, mierzy czasy odpowiedzi i pomaga sprawdzić, jak system zachowuje się pod różnymi obciążeniami.

Urealnienie testów

W realistycznych testach warto stosować różne techniki, które pomagają odwzorować zachowanie prawdziwych użytkowników. Jednym z takich sposobów jest tzw. think time, czyli czas, jaki użytkownik spędza pomiędzy kolejnymi akcjami, na przykład czytając treść strony, wypełniając formularz lub podejmując decyzję. Dodanie pauz między requestami sprawia, że scenariusz lepiej odzwierciedla rzeczywisty ruch, a wyniki testów są bardziej wiarygodne.

Informacje o tym znajdziemy też w dokumentacji Gatlinga:

Pauses are a crucial component of replicating real-world behavior, and it’s important to ensure they are placed appropriately throughout the scenario.

Problem: ręczne pauzy

Przy dużych scenariuszach pojawia się pytanie: czy naprawdę trzeba ręcznie dodawać .pause(...) po każdym exec(http(...))? To generuje powtarzalny kod i łatwo o błąd i może zostać uznane za naruszenie zasady DRY. Cały czas powtarzamy ten sam wzorzec: exec -> pauza. Taka duplikacja utrudnia utrzymanie (zmiana np. czasu trwania pauzy wymaga edycji wielu miejsc) i zwiększa ryzyko błędów. Naturalne było poszukanie sposobu na usprawnienie tego miejsca.

Rozwiązanie: implicit class

W Scali istnieje mechanizm implicit class, który pozwala rozszerzyć istniejące klasy o nowe metody. Ten sposób znany jest też jako wzorzec Pimp My Library.

Dzięki temu możemy dopisać własną metodę do obiektu ChainBuilder (podstawa DSL Gatlinga), która automatycznie dokłada pauzę po każdym wywołaniu.

Przykład kodu:

Helper z naszą dodatkową metodą zawierajacą pauze:

Scala
package pl.webqa

import io.gatling.core.Predef._
import io.gatling.core.structure.ChainBuilder
import io.gatling.http.request.builder.HttpRequestBuilder

import scala.concurrent.duration.{FiniteDuration, _}

object Helper {
  def execWithPause(request: HttpRequestBuilder, pauseDuration: FiniteDuration = 1.second): ChainBuilder = {
    exec(request)
      .pause(pauseDuration)
  }

  implicit class ChainBuilderOps(val chain: ChainBuilder) extends AnyVal {
    def execWithPause(request: HttpRequestBuilder, pauseDuration: FiniteDuration = 1.second): ChainBuilder = {
      chain.exec(Helper.execWithPause(request, pauseDuration))
    }
  }
}

Oraz przykład użycia na podstawie symulacji dostępnej w repozytorium Gatlinga, rozszerzone o użycie naszego execWithPause:

Scala

package pl.webqa

import Helper.{ChainBuilderOps, execWithPause} // ten import jest ważny jeżeli chcesz mieć możliwość używania execWithPause jako pierwszej metody lub kolejnej po standardowym exec
import io.gatling.core.Predef._
import io.gatling.http.Predef._

class BasicSimulation extends Simulation {


  val vu: Int = Integer.getInteger("vu", 1)

  val httpProtocol = http
    .baseUrl("https://api-ecomm.gatling.io")
    .acceptHeader("application/json")
    .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36")

  val sessionRequest = http("Session").get("/session") // przykładowy request

  val requests = exec(sessionRequest)
    .execWithPause(sessionRequest) // nasza metoda jako kolejna z rzędu

  val request2 = execWithPause(sessionRequest) // nasza metoda jako pierwsza

  private val scenario1 = scenario("Scenario 1")
    .exec(requests)
    .exec(request2)


  private val assertion = global.failedRequests.count.lt(1)

  setUp(
    scenario1.inject(atOnceUsers(vu))
  ).assertions(assertion).protocols(httpProtocol)
}

Dodatkowo metoda execWithPause zwraca obiekt ChainBuilder, co pozwala dalej łańcuchowo wywoływać kolejne metody Gatlinga (exec, if, repeat, during), stosując wzorzec method chaining. Dzięki temu scenariusze pozostają czytelne i spójne, nawet przy wielu krokach.

Dodatkowe możliwości

Skoro już mamy własne rozszerzenie DSL, nic nie stoi na przeszkodzie, by dodać kolejne usprawnienia, np.:

  • automatyczne logowanie requestów,
  • dodatkowe asercje,
  • metody do obsługi bardziej złożonych sekwencji.

Podsumowanie

Rozszerzenie DSL Gatlinga za pomocą implicit class to praktyczne rozwiązanie, które eliminuje powtarzalny kod, zmniejsza ryzyko błędów i ułatwia utrzymanie scenariuszy. Daje też punkt wyjścia do dalszych usprawnień, takich jak automatyczne logowanie czy dodatkowe walidacje. W połączeniu ze stosowaniem think time pozwala tworzyć scenariusze realistyczne i łatwe w utrzymaniu. Warto znać ten mechanizm i wykorzystywać go w większych projektach testowych.

Źródła / przydatne strony:

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Wymagane pola są oznaczone *


The reCAPTCHA verification period has expired. Please reload the page.