Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala / Lift: How do I write unit tests that test a snippet's response to different parameters

Tags:

scala

lift

I'm trying to write a Specs2 test that will test a snippet's output in response to different parameters which would normally be passed in from a template, but I haven't been able to figure out how to do it.

For instance, with the snippet callout in this div:

<div class="lift:Snippet.method?param1=foo"></div>

I'm passing the parameter param1 to the snippet. My snippet would look something like this:

class Snippet {
  def method(in:NodeSeq):NodeSeq = {
    val param1 = S.attr("param1") openOr ""
    param1 match {
      case "foo" => //do something
      case "bar" => //do something else
      case _ => //do yet another thing
    }
  }
}

So within my test, I want to test how the snippet responds to different param1 values

class SnippetTest extends Specification {
  "Snippet" should {
    "do something" in {
      val html = <ul>
          <li class="first">
          <li class="second">
          <li class="third">
        </ul>

      //I need to set param1 here somehow
      val out = Snippet.method(html)
      //then check that it did what it was supposed to
      out.something must be "xyz"
    }
  }
}

How do I set param1?

I am a big time scala and lift newb (coming from python+django), so if I'm barking up the wrong tree, please direct me to the right one. I think that might be the case, I've been googling on this all day and haven't found any questions remotely similar to this one.

Thanks,

Blake

like image 376
Blake Avatar asked Feb 01 '12 02:02

Blake


1 Answers

Ok, I've gotten this figured out. This question hasn't seen much interest, but in case anyone is out there googling with the same problem / question, here is how you do it:

Lift's "S" object needs to have our arbitrary attributes added to it so that it will give our snippet the attributes we want to test when asked. Unfortunately, there are 2 problems. First, the "S" object is only initialized when an http request is received. Second, S.attr is immutable.

Lift has a package called mockweb which allows you to make mock http requests. The documentation for this package typically talks about testing sessions and user logins and whatnot, but it also provides mechanisms for initializing "S" as part of a specification test.

The first problem, initializing S, is solved by defining our test class as an extension of WebSpec instead of Specification (WebSpec is part of the mockweb package and extends Specification), and calling "withSFor" during the specification definition, which will initialize "S"

The second problem, dealing with S.attr being immutable is solved with the "S" method "withAttrs". "withAttrs" executes a block of code you provide with both it's regular attributes, and attributes provided by you in a map. Your arbitrary attributes are only available from S.attr temporarily

Here is the test from my original question which has been modified to solve the 2 problems:

import net.liftweb.mockweb._

class SnippetTest extends WebSpec {
  "Snippet" should {
    "do something" withSFor("/") in {
      val html = <ul>
          <li class="first">
          <li class="second">
          <li class="third">
        </ul>

      //here I set param1
      var m = new HashMap[String, String]
      m += "param1" -> "foo"

      val s = new Snippet()

      //then tell S to execute this block of code
      //with my arbitrary attributes.
      //'out' will be the NodeSeq returned by s.method
      val out = S.withAttrs(S.mapToAttrs(m)){
        s.method(html)
      }

      //then check that it did what it was supposed to
      out.something must be "xyz"
    }
  }
}

edit: clarity

like image 123
Blake Avatar answered Jan 28 '23 20:01

Blake