2

I'm using akka-http for the first time - my usual web framework of choice is http4s - and I'm having trouble getting the way I usually write endpoint unit tests to work with the route testing provided by akka-http-testkit.

Generally, I use ScalaTest (FreeSpec flavour) in order to set up an endpoint call and then run several separate tests on the response. For akka-http-testkit, this would look like:

import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.testkit.ScalatestRouteTest
import org.scalatest.{FreeSpec, Matchers}

final class Test extends FreeSpec with ScalatestRouteTest with Matchers {

  val route: Route = path("hello") {
    get {
      complete("world")
    }
  }

  "A GET request to the hello endpoint" - {
    Get("/hello") ~> route ~> check {
      "should return status 200" in {
        status should be(StatusCodes.OK)
      }

      "should return a response body of 'world'" in {
        responseAs[String] should be("world")
      }

      //more tests go here
    }
  }
}

This errors with

java.lang.RuntimeException: This value is only available inside of a `check` construct!

The problem is the nested tests inside the check block - for some reason, values like status and responseAs are only available top-level within that block. I can avoid the error by saving the values I'm interested in to local variables top-level, but that's awkward and capable of crashing the test framework if e.g. the response parsing fails.

Is there a way around this, without putting all my assertions into a single test or performing a new request for each one?

Astrid
  • 1,808
  • 12
  • 24
  • re: `Is there a way ... without ...?` As far as I know -- no. All working examples I've seen put _all_ the `should`s relating to a given request/response in the same `check` block. – Jesse Chisholm Oct 04 '19 at 00:01

1 Answers1

1

You can group your test like that

"A GET request to the hello endpoint should" in {
   Get("/hello") ~> route ~> check {
       status should be(StatusCodes.OK)
       responseAs[String] should be("world")
       //more tests go here
   }
}
Djiggy
  • 602
  • 6
  • 20
  • This is the "all my assertions in a single test" way I mentioned in the question I didn't want to do. I'd like separate tests that succeed/fail separately for the status code vs the response. – Astrid Jun 02 '18 at 07:55