Why use Specs2 over JUnit?

760 views Asked by At

We went through online material such as scalatest site. What are advantages of using scala testing framework Specs2? How does it add to the project over JUnit?

1

There are 1 answers

1
millhouse On

I'm a little reluctant to answer this because it's a quite subjective thing.

But I could summarise it as "In the same way Scala gives you new and cleaner ways to solve problems over Java, Specs2 gives you new and cleaner ways to test over JUnit".

Some quick examples:

Mockito is a first-class citizen

Mockito is my favourite JVM mocking library; using it with Specs2 is as simple as mixing in a trait and you get a nice DSL for verification:

class MySpec extends Specification with Mockito { 
   // Setup:
   val mockConnection = mock[Connection]

   ...

   // Verification: (in a test)
   there was one(mockConnection).get("www.google.com")
}  

ScalaCheck is a first-class citizen

ScalaCheck can save a heap of time "fuzzing" inputs to your functions, and again, a simple trait mixin gets you all of its power within your Specs2 tests.

Run a test in a Scope

Ever had a problem where tests would work on your machine but break elsewhere, because your machine ran them in a certain order? Or got into "mocking hell" due to interactions between stubbed collaborator behaviour? Specs2 lets you put the entire test into a Scope to contain all of that state and stop it from leaking into other tests:

class AnotherSpec extends Specification with Mockito {

  class FooScope extends Scope {
    val mockResponse = mock[Response]
    val mockConnection = mock[Connection]
    ...
    mockConnection.execute returns mockResponse

    def frobulate(s:String) = {
      // Use mockResponse, mockConnection, etc ...
    }
  }

"My thing" should {

  "Do stuff" in new FooScope {
    frobulate("hello")

    there was one(mockConnection).post(...)
  }
}

Scopes help you DRY up your tests as well as stop state leaks between them.

Plus

  • "Blocks" to group related tests ("My thing" should)
  • Readable, space-separated test names ("throw an exception if argument < 0" in)
  • Readable DSL for matching (result must have length(7))
  • Matchers for Scala-idiomatic types (result must beNone)
  • Easily temporarily disable a test with pending
  • Generate HTML reports/output with a DSL

Downsides

In an attempt to make this answer slightly more objective, I should also point out this article by the esteemed Bill Venners about compile time which points out that a Specs2 mutable.Specification, due to large numbers of implicits and function declarations, is almost an order-of-magnitude slower to compile than a roughly-equivalent JUnit test. It also does not scale well over large numbers of tests. Or at least it didn't when the article was written in early 2013. There are now approaches you can use to address this.