简体   繁体   中英

Custom DSL by extending Gatling: How to Scala?

We're using Gatling to load test our application (and it works great). We're attempting to DRY up some of the code by making composable extensions on the Gatling classes (like ScenarioBuilder / ChainBuilder / etc. found in io.gatling.core.structure ).

Here is an example of one of our scenarios:

val scn = scenario("Whatever")
  .exec(Authentication.FeederLogin(userCsvFile, password))
  .exec(User.ExtractId(User.SignIn()))
  .exec(FindPeople(50, "personIds"))

  // SPA load
  .exec(User.FetchLandingPageFor("${userId}"))

  .during(durationSeconds.seconds) {
    pace(3.seconds, 8.seconds)
      .exec(Person.Search("${personIds.random()}"))
      .pause(3.seconds, 10.seconds)

      // start the upload
      .exec(Upload.create())
  }

What we'd like to do is start to make some of that composable so we can re-use them in other scenarios. Something like this:

val scn = scenario("Whatever")
  .login()

  .during(durationSeconds.seconds) {
    pace(3.seconds, 8.seconds)
      .uploadFor("${personIds.random()}")
  }

// ...

object WhateverScenarios {
  implicit class ScenarioBuilderWithWhatevers(b: ScenarioBuilder) {

    def login() : ScenarioBuilder = {
      b.exec(Authentication.FeederLogin(userCsvFile, password))
      .exec(User.ExtractId(User.SignIn()))
      .exec(FindPeople(50, "personIds"))
    }

    def uploadFor(whom : String) : ScenarioBuilder {
      b.exec(Person.Search("${personIds.random()}"))
      .pause(3.seconds, 10.seconds)

      // start the upload
      .exec(Upload.create())
    }
  }
}

Full disclosure; I'm not super familiar with Scala. This works, but the problem is in the uploadFor in that at that point it's working with a ChainBuilder vs. a ScenarioBuilder .

I thought

Oh, simple! Just use generics!

Except I cannot get it to work :( It looks like most of these extend StructureBuilder[T] but I cannot seem to get a generic definition defined where I can use my WhateverScenarios in any context of a StructureBuilder[T] .

Thanks in advance for any information that can be provided.

So I was able to get past my issue, but I'm not entirely sure why I had to do this. What fixed my issue is the following:

object WhateverScenarios {
  implicit class StructureBuilderWithWhatevers[B <: io.gatling.core.structure.StructureBuilder[B]](b: B) {

    def login() : B = {
      b.exec(Authentication.FeederLogin(userCsvFile, password))
      .exec(User.ExtractId(User.SignIn()))
      .exec(FindPeople(50, "personIds"))
    }

    def uploadFor(whom : String) : ScenarioBuilder {
      b.exec(Person.Search("${personIds.random()}"))
      .pause(3.seconds, 10.seconds)

      // start the upload
      .exec(Upload.create())
    }
  }
}

The thing that was throwing me for a loop, was originally I tried to define it like this:

object WhateverScenarios {
  implicit class StructureBuilderWithWhatevers[B <: StructureBuilder[B]](b: B) {
  // ...
}

But when I did that, it didn't recognize login or uploadFor as being part of either ScenarioBuilder or ChainBuilder . Not sure why, but I had the specify the fully qualified package name for it to work ¯\\_(ツ)_/¯

Edit

Turns out that the fully qualified package name was some weird artifact that I had on my machine. Doing a ./gradlew clean fixed the issue and I no longer have to use the fully qualified path name.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM