The document discusses testing a REST API built with the Spray toolkit in Scala. It provides an example of building a simple REST service with Spray, including defining routes and request/response handling. It then demonstrates how to test the service using Spray's testkit, including making requests, checking responses, and handling rejections. It recommends testing the REST layer independently of underlying services through dependency injection.
11. Example - replace route
class RestService extends HttpServiceActor
with SimpleService {
def receive = runRoute(route)
def route =
simpleRoute
}
12. Example - test
import org.scalatest. {Matchers, FlatSpec}
import spray.testkit.ScalatestRouteTest
class SimpleServiceSpec extends FlatSpec with Matchers
with ScalatestRouteTest
with SimpleService {
def actorRefFactory = system // boilerplate
"A SimpleService" should "return 'ok' for GET request on /" in {
Get("/") ~> simpleRoute ~> check {
responseAs[ String] should be ("ok")
}
}
}
13. Test API
status.intValue
headers
responseAs[T] // (un)marshalling - String for free
rejections // little tricky when want to test deeper
Get("/users?format=pretty" )
Post("/user", """{"name": "pawel"}""" )
Put("/user/1", """{"name": "kopiczko"}""" )
Delete("/user/1")
Get("/mail/all") ~> Authorization(BasicHttpCredentials ("pawel", ""))
14. Test Rejection
def deleteRoute =
delete {
path("user" / IntNumber) { id =>
userService.delete(id)
complete( "Deleted user with id " + id)
}
}
Get("/user/1") ~> deleteRoute ~> check {
rejection should be ( MethodRejection (HttpMethods.DELETE))
}
OK, but...
15. Test Rejection
Get("/user/1") ~> deleteRoute ~> check {
status.intValue should be ( 405)
}
[info] - should not allow GET request on /user *** FAILED ***
[info] Request was rejected with List(MethodRejection(DELETE))
16. Test Rejection
Get("/user/1") ~> {
handleRejections( RejectionHandler .Default) {
deleteRoute
}
} ~> check {
status.intValue should be ( 405)
}
OK
17. Dependency Injection
Route is a method - pass arguments
def userRoute(service: UserService) =
get("user" / IntNumber) { id =>
complete {
userService.get(id)
}
}
Get("/user/1") ~> userRoute(userServiceMock) ~> check
18. Dependency Injection
● Test the REST layer responsibility
● Do NOT test underlying services
● There is another place for that