简体   繁体   中英

Lift/Scala: How do I unit test rest response of an api?

I would like to test the response of the following rest api for valid and invalid requests. For exaple given a valid request it should return 200 and for invalid request it should return 400. How can this be done?

object API extends RestHelper {
  implicit val timeout:Timeout = new FiniteDuration(200, SECONDS)
  def init() {
    LiftRules.dispatch.append(API)
  }

  serve {
    case "api" :: "xweb" :: "v1" :: "search" ::  z JsonPost request => {
      RestContinuation.async({
        reply => {
          val future = Promise[String].future
          future.map(x => new InMemoryResponse(x.getBytes("UTF-8"), List(), List(), 200))

          future.onSuccess({
            case response: InMemoryResponse => {
              reply(response)
            }
            case _ => {
              reply(new InternalServerErrorResponse())
            }
          })
          future.onFailure({
            case _ => reply(new InternalServerErrorResponse())
          })
        }
      })
    }

    case "api" :: "xweb" :: "v1" :: "search" ::  _ Get _ => {
      new BadResponse()
    }

    case "api" :: "xweb" :: "v1" :: "search" ::  _ Post _ => {
      new BadResponse()
    }
  }
}

I have seen this link but it seems to be testing the S object and the Req object. Also this link about Specs2; I didnt find anything about testing http responses.

Please advise. Thank you.

Note: generally you'll get faster responses by far if you post to the Lift list at https://groups.google.com/forum/#!forum/liftweb . It's much more closely monitored and usually you'll get a response within 24 hours.


One of the really cool things about RestHelper is that it reuses Scala abstractions. In particular, a RestHelper is just a (Req)=>()=>Box[LiftResponse] , that is any instance of RestHelper is a function that takes a Req and produces a function that returns a Box[LiftResponse] . That extra indirection through a secondary function is mostly abstracted away from you and due to some of the variations on request/response handling that Lift has to deal with internally.

During testing, once you have a Req (which your first link describes how to get), you can just apply your RestHelper :

"My API when handling bad requests" should {
  val testUrl = "/api/xweb/v1/search/15"
  val testBody = "Invalid body"

  "my spec" withReqFor(testUrl) withPost(testBody) in { req =>
    API.apply(req)() must beLike { // the second set of parens unwraps the ()=>Box[LiftResponse]
      case Full(response) =>
        code must beAnInstanceOf[BadResponse] 
    }
  }
}

Now one thing I did notice in your non-bad-response handling is that you use RestContinuation.async . The mechanism for this is a little different than the others because of how asynchronous requests have to be plumbed internally at the container level. If you hit that code path, your apply will actually throw a ContinuationException . That ContinuationException in turn will carry a function that does the actual response handling.

For these cases, I would suggest the easiest thing would be to split everything but the RestContinuation setup into a function, and test that function. You can test it by catching the ContinuationException and invoking the internals of it, but it's not particularly straightforward and you won't gain much vs just testing the function that produces the response directly, and letting the async wrapper do its work at runtime.

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