Extending ScalatraFunSuite

I’ll keep this one very short and to the point: I’ve been working extensively with Scalatra and Scalate recently, and it’s been great. My only minor problem has been with the bundles testing capabilities with Scalatra, namely the ScalatraFunSuite.

It lets you very easily test your Scalatra filters or servlets, but the number of things you can assert on is a bit limited. You can check status (to ensure you get a 200 instead of a 404 or a 500, for instance), and you can assert things about the contents of the response body, such as if it contains an expected string. All well and good, but not enough for my test-driven proclivities.

So I did a bit of tinkering, and came up with a nice clean way to grab things such as cookies, response values being passed to the template, the name of the Scalate template being called, and so forth.

I want to be able to write a test like this:

test("edit the organization data") {
    get(ORGANIZATION_URL) {
      status should equal(200)
      assert(template.endsWith(OrganizationController.ORGANIZATION_TEMPLATE))
    }
  }

For instance, where I assert that the template that got called was a certain template that I expect.

It turns out this isn’t very hard – just stick another Filter in the chain when you set up your test, like so:

addFilter(classOf[TestFilter], "/*")
   addFilter(new CommonFilter, "/*")

And yes, I am using a different method invokation on the second line – I do this intentionally, so I can control creation of the servlet class under test, as I use Guice-servlet to inject all it’s service dependencies, and at test-time, I do this with implicit parameter – but that’s a whole ‘nother post icon smile Extending ScalatraFunSuite

Anyway, TestFilter, as you might imagine, gives me “hooks” that I can assert on later. It looks like this:

object TestFilter {
  var lastURI: String = null
  var values: Map[String, AnyRef] = Map()
  def template = values("scalateTemplates").asInstanceOf[List[String]].head
  val cookies = ListBuffer[Cookie]()
}

class TestFilter extends Filter {

  def destroy() {}

  def init(conf: FilterConfig) {}

  override def doFilter(request: ServletRequest, response: ServletResponse, filterChain: FilterChain) {
    val wrappedResponse = new ResponseWrapper(response.asInstanceOf[HttpServletResponse])

    val httpRequest = request.asInstanceOf[HttpServletRequest]
    lastURI = httpRequest.getRequestURI
    filterChain.doFilter(request, wrappedResponse);
    val names = httpRequest.getAttributeNames
    while(names.hasMoreElements) {
      val name = names.nextElement.asInstanceOf[String]
      val value = httpRequest.getAttribute(name)
      println(name + ":" + value)
      values += (name -> value)
    }
  }

  class ResponseWrapper(val response: HttpServletResponse) extends HttpServletResponseWrapper(response) {
    override def addCookie(cookie: Cookie) {
      super.addCookie(cookie)
      cookies += cookie
    }
  }
}

That’s all there is to it – now I can call my servlet under test just like in the first code snippet, and assert on values being sent to the template, on the name of the template, on cookies, and so forth.

That’s it! Hope this turns out to be useful to some other Scalatra aficionados out there!

Principles and Practices

Tired of the Software Development Grind? Know it can be done better? Check out my book: Principles and Practices of Software Craftsmanship or sign up for my Craftsmanship Dispatches newsletter.

Published: April 28 2011

  • tags: