Search code examples
scalaplayframeworkscalatestintellij-13

Changes to build.sbt to enable ScalaTest tests to run with Scala Play


I am following the docs here, and this does not seem to work at all; but I'm not even sure what am I doing wrong here.

For a start, just adding the given snippet in a project/Build.scala file causes a compile error; so that's a non-start. Wrapping it inside an object which extends Build (as in the SBT example) does not cause a compile error, but the tests are not run.

Eventually, I've added the following to my build.sbt

libraryDependencies ++= Seq(
    "org.scalatestplus" %% "play" % "1.0.0" % "test",
    ...

this is marginally better, but in IntelliJ, my ApplicationSpec has all sorts of compilation error:

import org.scalatestplus.play._

import scala.collection.mutable.Stack

class ApplicationSpec extends PlaySpec {

  "A Stack" must {
    "pop values in last-in-first-out order" in {
      val stack = new Stack[Int]
      stack.push(1)
      stack.push(2)
      stack.pop() mustBe 2
      stack.pop() mustBe 1
    }
    "throw NoSuchElementException if an empty stack is popped" in {
      val emptyStack = new Stack[Int]
      a [NoSuchElementException] must be thrownBy {
        emptyStack.pop()
      }
    }
  }
}

must, mustBe and a are not recognized. Finally, if I try to run activator test I get:

sentinel/test:definedTests
java.lang.NoSuchMethodError: org.specs2.runner.Fingerprints$.fp1()Lorg/specs2/runner/SpecificationFingerprint;
    at org.specs2.runner.Specs2Framework.fingerprints(SbtRunner.scala:23)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at sbt.TestFramework$.getFingerprints(TestFramework.scala:113)
    at sbt.Tests$$anonfun$discover$1.apply(Tests.scala:242)
    at sbt.Tests$$anonfun$discover$1.apply(Tests.scala:242)
    at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
    at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
    at scala.collection.immutable.List.foreach(List.scala:318)
    at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:251)
    at scala.collection.AbstractTraversable.flatMap(Traversable.scala:105)
    at sbt.Tests$.discover(Tests.scala:242)
    at sbt.Defaults$$anonfun$detectTests$1.apply(Defaults.scala:556)
    ...
[error] (sentinel/test:definedTests) java.lang.reflect.InvocationTargetException

Essentially, an epic fail - it would be great if the docs were a bit more specific in what is required and what is expected for all the machinery to work: as things stand, it's kinda difficult to untangle the mess.

I've been googling and looking here on stack overflow for hours today, looked at the ScalaTestPlus docs (well, the whole two paragraphs of it...) and tried many variations, all to no avail.

The full project's code is on github.

Worth noting that if I give in to the "power-of-bad-documentation" and I use Specs2, then tests run correctly (at least from inside Intellij, and as far as the 'hello world' example goes).

I would still much prefer to using ScalaTest (can't really see why I need to learn TWO testing frameworks, really) - so, any help would be appreciated.


Solution

  • In the end, it turned out it was indeed a library version mismatch, but one I hadn't anticipated.

    It revolves around the fact that I have a sub-project in my sbt build, which works just fine, but was importing ScalaTest 2.2.1, while I was using 2.1.7 to make it work with ScalaTest+ 1.1.0 - however, using ScalaTest 2.1.7 (which, indeed works with ST+ 1.1.0) only for the 'top-level' project was causing the weirdness around the abstract class, etc.

    The Versions, Versions, Versions page has now been updated by Bill, and the fix has been to use ScalaTest 2.2.1, ScalaTestPlus 1.2.0 and Play 2.3.0 - which all play nice together.

    Updated - the above still caused tests to fail via sbt/activator test, I could only run the tests via IntelliJ: the fix has been to update the build.sbt to use Scala 2.11

    In the end, to make this work, this is what I have in my build.sbt:

    name := "sentinel"
    
    version := "0.2-SNAPSHOT"
    
    organization := "AlertAvert.com"
    
    scalacOptions ++= Seq("-deprecation", "-feature", "-language:postfixOps")
    
    // The REST project depends on Core Sentinel classes
    lazy val sentinel_core = project
    
    lazy val sentinel = (project in file("."))
        .enablePlugins(PlayScala)
        .aggregate(sentinel_core)
        .dependsOn(sentinel_core)
    
    scalaVersion := "2.11.1"
    
    libraryDependencies ++= Seq(
      "org.scalatest" %% "scalatest" % "2.2.1" % "test",
      "org.scalatestplus" %% "play" % "1.2.0" % "test",
      cache
    )
    

    (I'm reproducing it in its entirety, so that if someone else has the same problem, they'll see it - it infuriates me when people only paste a fragment and some key essentials are omitted :)

    Major credits to Bill Venners for the help and guidance.