Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debug scala sbt integration tests in IntelliJ

I use SBT plugin for IntelliJ and I have created a scala project with the following build settings: Build.scala:

lazy val root =
    Project("root", file("."))
      .configs( IntegrationTest )
      .settings( Defaults.itSettings : _*)

build.sbt:

<setting some parameters>
libraryDependencies += "org.scalatest" % "scala-test_2.10" % "1.0.8" % "test,it"

Now I end up with src/main, src/test and src/it in my project structure. I now can run compile, test and it:test from both SBT console in IntelliJ and in SBT repl. So all is great at this point.

The only problem I yet to figure out is how to debug integration tests. I have added a scalatest configuration that runs test:compile before launch and this gets me going with unit test debug. I try to create a new Debug configuration for integration tests, but can't figure out how to point it to src/it to find the tests. I tried to debug a specific test by changing "Test kind" to class and pointing to a specific test class, but keep getting the following exception:

Unable to load a Suite class. This could be due to an error in your runpath. Missing class: it.AddPersonSpec
java.lang.ClassNotFoundException: it.AddPersonSpec
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at org.scalatest.tools.Runner$$anonfun$22.apply(Runner.scala:1962)
    at org.scalatest.tools.Runner$$anonfun$22.apply(Runner.scala:1960)
    at scala.collection.TraversableLike$$anonfun$filter$1.apply(TraversableLike.scala:264)
    at scala.collection.immutable.List.foreach(List.scala:318)
    at scala.collection.TraversableLike$class.filter(TraversableLike.scala:263)
    at scala.collection.AbstractTraversable.filter(Traversable.scala:105)
    at org.scalatest.tools.Runner$.doRunRunRunDaDoRunRun(Runner.scala:1960)
    at org.scalatest.tools.Runner$$anonfun$runOptionallyWithPassFailReporter$2.apply(Runner.scala:850)
    at org.scalatest.tools.Runner$$anonfun$runOptionallyWithPassFailReporter$2.apply(Runner.scala:849)
    at org.scalatest.tools.Runner$.withClassLoaderAndDispatchReporter(Runner.scala:2221)
    at org.scalatest.tools.Runner$.runOptionallyWithPassFailReporter(Runner.scala:848)
    at org.scalatest.tools.Runner$.run(Runner.scala:706)
    at org.scalatest.tools.Runner.run(Runner.scala)
    at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.runScalaTest2(ScalaTestRunner.java:144)
    at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.main(ScalaTestRunner.java:35)

When I look into "Project Structure" -> "Modules", I see that src/it/scala is under "Test source folders" category. Not sure where else to look now ...

Update: I had an sbt configuration problem. I used project name "root" in Build.scala and other name in build.sbt. This created two module configurations for IntelliJ. I fixed that and now I can't reconcile IntelliJ and sbt settings for my only module.

The effect that I see now is that after I run gen-idea from sbt console and reload the project, my integration test looks fine for a little while (while sbt is being updated). I can even get to a definition of 'And' method defined in Scalatest. After a few seconds, however, it 'looses' a reference to scalatest lib (when sbt is done updating). When I go to "Project Structure" -> "Modules", I don't see src/it/scala anywhere. If I add it manually to test source IntelliJ can resolve scalatest again. After I run gen-idea it disappears. Rinse and repeat.

Note that remote debugger solution proposed by Eugene does not work for me. I run sbt as a server and attach IntelliJ, but when I run it:test it does not stop on breakpoint. I think it is because integration test source is not considered to be a part of source/test by IntelliJ.

If I first add src/it/scala in project settings and then try to use remote debugger before running gen-idea, then SBT crashes with OutOfMemory. So I'm completely stumped at this point...

Any thoughts are highly appreciated.

like image 282
Tim Avatar asked Apr 30 '14 01:04

Tim


2 Answers

In IntelliJ, right-click on the project, go to Open Module Settings, select the Paths tab, and change Test output path from .../target/scala-2.11/test-classes to .../target/scala-2.11/it-classes. That way, you can debug integration tests just like normal tests.

You have to change it back before debugging a normal test. Also, importing the sbt project into IntelliJ again wipes the setting.

like image 151
Dirk Groeneveld Avatar answered Nov 09 '22 10:11

Dirk Groeneveld


That's how I debug SBT projects:

  1. Add to ~/.sbtconfig

    SBT_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"

  2. Attach Intellij Idea to running sbt process with Remote Debug configuration: http://www.jetbrains.com/idea/webhelp/run-debug-configuration-remote.html

  3. Profit! Add breakpoints in you project code.

Note that in this configuration Idea will be attached to SBT JVM, not only to you project files, so you can debug your build file too.

If you use "fork in Test := true" option I guess it's possible to pass this config with jvm args config option, but as I can see from you project definition, you don't fork your tests.

like image 44
Eugene Zhulenev Avatar answered Nov 09 '22 09:11

Eugene Zhulenev