5

I looked at spray 1.3.1 testkit documentation but could not find a proper example for what I need below: I have this sample spray 1.3.1 service

trait MyService extends HttpServiceActor {
  def receive = runRoute(routes)

  val isAliveRoute = path("isalive") {
    get {
        complete("YES")
    }
  }
  val routes = isAliveRoute
}

I'm trying to test it with spray test-kit but failing to do so here is my TestCase

@RunWith(classOf[JUnitRunner])
class MyServiceTest extends FlatSpec with ScalatestRouteTest with ShouldMatchers with MyService {
  "The service" should "return a greeting for GET requests to the isalive" in {
    Get() ~> isAliveRoute ~> check {
      responseAs[String] should be("YES")
    }
  }
}

However I get

Error:(15, 87) illegal inheritance; superclass FlatSpec is not a subclass of the superclass HttpServiceActor of the mixin trait MyService class MyServiceTest extends FlatSpec with ScalatestRouteTest with ShouldMatchers with MyService { ^
^

and:

Error:(17, 11) could not find implicit value for parameter ta: MyServiceTest.this.TildeArrow[spray.routing.RequestContext,Unit] Get() ~> isAliveRoute ~> check { ^

Are there ways around this? Can I have my service extend HttpServiceActor and still be able to test it with scalatest and spray testkit? if so how? I want to continue extending HttpServiceActor makes life easier and code more compact and readable. But I would also like to test it with scalatest.

so i tried updating the code as comment said to split to trait and service as in: https://github.com/spray/spray-template/blob/on_spray-can_1.1/src/main/scala/com/example/MyService.scala

class MyServiceActor extends Actor with MyService {
  def actorRefFactory = context
  def receive = runRoute(routes)
}

trait MyService extends HttpService {

  val isAliveRoute = path("isalive") {
    get {
        complete("OK")
    }
  }
  val routes = isAliveRoute
}




@RunWith(classOf[JUnitRunner])
class MyServiceTest extends FlatSpec with ShouldMatchers with MyService with ScalatestRouteTest {
  def actorRefFactory = system

  "The service" should "return a greeting for GET requests to the isalive" in {
    Get() ~> isAliveRoute ~> check {
      responseAs[String] should be("YES")
    }
  }
}

but i get:

Testing started at 13:26 ... [DEBUG] [05/14/2014 13:26:25.813] [ScalaTest-run] [EventStream(akka://com-server-web-conf-MyServiceTest)] logger log1-Logging$DefaultLogger started [DEBUG] [05/14/2014 13:26:25.814] [ScalaTest-run] [EventStream(akka://com-server-web-conf-MyServiceTest)] Default Loggers started Request was not handled org.scalatest.exceptions.TestFailedException: Request was not handled at spray.testkit.ScalatestInterface$class.failTest(ScalatestInterface.scala:25) at

Jas
  • 14,493
  • 27
  • 97
  • 148
  • 2
    It works if you split up your code into the route part which just extends from `HttpService` and move the actor relevant stuff into the concrete class implementing the actor. See how it's done in the spray-template: https://github.com/spray/spray-template/blob/on_spray-can_1.1/src/main/scala/com/example/MyService.scala – jrudolph May 14 '14 at 08:53
  • @jrudolph updated question, i tried that it helped, but i still have an error... – Jas May 14 '14 at 10:37
  • 2
    That's now a genuine test failure as your request (`Get()`) didn't handle URLs with an empty path. If you want to have actual failure responses (404) to be generated in that case you have use `Get() ~> sealRoute(isAliveRoute) ~> ...`. – jrudolph May 14 '14 at 13:44
  • @jrudolph can be posted as answer.. – Jas May 22 '14 at 11:33

1 Answers1

2

I had similar problem with one difference. At complete statement I had sending message to another actor, so I needed actor functionality to test behavior. I solved it that way:

trait MyService extends HttpService {
 val myActor: ActorRef
 val homeS: ActorRef 
 (...)

and sending message inside get to

path("isalive") { get {
ctx: RequestContext => homeS.tell(ctx, myActor ) }
//on homeS actor:
def receive = {
case ctx: RequestContext =>
  ctx.complete( ... )

but if you don't need actor functionality of in MyService then better is to do like @jrudolph said in comment.

Full code here: https://github.com/kastoestoramadus/simple_zookeeper.git

Waldemar Wosiński
  • 1,490
  • 17
  • 28