Testing

Of course, Akka would not be Akka if it did not provide a nice DSL for testing HTTP routes. The DSL allows us to test routes in a way that it is not needed to start a real server. It is possible to provide a mock implementation of the business logic to test routes in isolation. In our case, the logic is so simple that it actually makes sense to test the app as a whole, the same way we did in the http4s case.

The definition of the specification should not be surprising:

class RoutesSpec extends WordSpec with Matchers with ScalaFutures with ScalatestRouteTest with Routes {

override lazy val config: Config = Config.load()

DB.initialize(config.database)

override lazy val inventory: ActorRef = system.actorOf(InventoryActor.props, "inventory")
...
}

The good news is that ScalatestRouteTest already provides a definition for the actor system and materializer so we don't need to initialize them before the test and close after the test. The Routes are the same Routes we defined earlier and are about to test now. We still have abstract definitions of config and inventory here, so provide an implementation for them.

And this is how we can test a route:

"Routes" should { "be able to add article (POST /articles/eggs)" in {
val request = Post("/articles/eggs")
request ~> routes ~> check {
status shouldBe StatusCodes.Created
contentType shouldBe ContentTypes.`application/json`
entityAs[String] shouldBe """{"name":"eggs","count":0}"""
}
}}

First, we define the request we want the route to be checked against. Then we transform it with the route to the response, which in turn gets transformed into check. In the body of check, we can refer to the properties of the response in a simple way. 

The routes in request ~> routes ~> check refer to the field defined in the Routes trait.

Similarly, it is possible to create a request with a body and use it to test a route that expects such request:

"be able to restock articles (POST /restock)" in {
val restock = RestockArticles(Map("eggs" -> 10, "chocolate" -> 20))
val entity = Marshal(restock).to[MessageEntity].futureValue
val request = Post("/restock").withEntity(entity)
request ~> routes ~> check {
status shouldBe StatusCodes.OK
contentType shouldBe ContentTypes.`application/json`
entityAs[String] shouldBe """{"stock":{"eggs":10,"chocolate":20}}"""
}
}

Here we Marshal the restock case class to Entity the same way it worked on routes. .futureValue is from the ScalaTest's ScalaFutures helper. The rest of the snippet is very similar to the previous example.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.187.108