The Artima Developer Community
Sponsored Link

Angle Brackets and Curly Braces
On Dasher
by Bill Venners
December 26, 2008
Summary
The latest version of ScalaTest includes a trait named SpecDasher, which when mixed into a Spec facilitates a more concise expression of specification-style tests. It is deprecated, however, and may be removed in a future release depending on user feedback. What's your opinion?

Advertisement

The basic form of writing a Spec in ScalaTest looks a bit like it does in Ruby's RSpec. You name the subject (class or other entity) you are specifying and testing with "describe" and the actual behavior specifications and accompanying tests (called examples in BDD terminology) with "it." Here's a simple Spec:

import org.scalatest.Spec
import scala.collection.mutable.Stack

class StackSpec extends Spec {

  describe("A Stack") {

    it("should pop values in last-in-first-out order") {
      val stack = new Stack[Int]
      stack.push(1)
      stack.push(2)
      assert(stack.pop() === 2)
      assert(stack.pop() === 1)
    }

    it("should throw NoSuchElementException if an empty stack is popped") {
      val emptyStack = new Stack[String]
      intercept[NoSuchElementException] {
        emptyStack.pop()
      }
    }
  }
}

Executing a Spec will produce specification-style output. For example, running StackSpec from within the Scala interpreter, like this:

scala> (new StackSpec).execute()

Will yield:

A Stack
- should pop values in last-in-first-out order
- should throw NoSuchElementException if an empty stack is popped

With SpecDasher, you can write the same specification a bit more concisely, like this:

import org.scalatest.Spec
import org.scalatest.SpecDasher
import scala.collection.mutable.Stack

class StackDashSpec extends Spec with SpecDasher {

  "A Stack" -- {

    "should pop values in last-in-first-out order" - {
      val stack = new Stack[Int]
      stack.push(1)
      stack.push(2)
      assert(stack.pop() === 2)
      assert(stack.pop() === 1)
    }

    "should throw NoSuchElementException if an empty stack is popped" - {
      val emptyStack = new Stack[String]
      intercept[NoSuchElementException] {
        emptyStack.pop()
      }
    }
  }
}

Running StackDashSpec will produce the same specification-style output as the previous one:

scala> (new StackDashSpec).execute()
A Stack
- should pop values in last-in-first-out order
- should throw NoSuchElementException if an empty stack is popped

Trait SpecDasher enables this syntax by offering an implicit conversion from String to a class named Dasher, which has - and -- methods. In ScalaTest 0.9.4, trait Spec already mixes in SpecDasher, because I showed this syntax in Programming in Scala working just in a plain old Spec. ScalaTest 0.9.4 is the version that's illustrated in the book, and I wanted all the code in the book to work, but after the book went to the printer I began to have second thoughts about the dashes style. If I do end up leaving SpecDasher in the API, I will definitely change Spec so that it doesn't already mix in SpecDasher. This way users will have to explicitly invite in these implicit conversion by mixing in SpecDasher explicitly in their own Specs.

However, I am also considering simply dropping SpecDasher entirely, which is why it is deprecated. Although it does clear out just about all clutter around a Spec, leaving just the specification text and the test code, the difference between a describe clause (denoted by two dashes) and an it clause (denoted by one dash) may be less obvious in dashes style. Another advantage that I think explicit "it" clauses may have is that they may make it more likely people will start the spec text with a verb, usually either "should" or "must".

Also, I didn't provide a way in dashes style to "ignore" a test or place a test into groups, because to do so would have added more syntax to learn for both readers and writers of the tests. If you want to do either of those activities, therefore, you'll need to switch back to the default style. Here's how you'd ignore the first test, and place it in the SlowTests group:

ignore("should pop values in last-in-first-out order", SlowTests) {
  val stack = new Stack[Int]
  stack.push(1)
  stack.push(2)
  assert(stack.pop() === 2)
  assert(stack.pop() === 1)
}

Although it is kind of cool to include a class named after one of Santa's reindeer in an API, in general I subscribe to the philosophy that you're not done when you can't think of anything else to add. Rather, you're done when you can't think of anything else to take out. If I do remove SpecDasher, those that like it could still use it by grabbing the source code (which is very small) and mixing it in locally. But I'd like to hear what others think, because I also subscribe to the philosophy that usually you should try to give the people what they want. Please post your opinion in the discussion forum for this blog post.

Talk Back!

Have an opinion? Readers have already posted 1 comment about this weblog entry. Why not add yours?

RSS Feed

If you'd like to be notified whenever Bill Venners adds a new entry to his weblog, subscribe to his RSS feed.

About the Blogger

Bill Venners is president of Artima, Inc., publisher of Artima Developer (www.artima.com). He is author of the book, Inside the Java Virtual Machine, a programmer-oriented survey of the Java platform's architecture and internals. His popular columns in JavaWorld magazine covered Java internals, object-oriented design, and Jini. Active in the Jini Community since its inception, Bill led the Jini Community's ServiceUI project, whose ServiceUI API became the de facto standard way to associate user interfaces to Jini services. Bill is also the lead developer and designer of ScalaTest, an open source testing tool for Scala and Java developers, and coauthor with Martin Odersky and Lex Spoon of the book, Programming in Scala.

This weblog entry is Copyright © 2008 Bill Venners. All rights reserved.

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use