IntelliJ cannot find Scala integration test framework - scala

I have configured a Scala project for integration tests as described in https://www.scala-sbt.org/1.x/docs/Testing.html.
I can get the integration tests executed from sbt, but not from IntelliJ. IntelliJ seems to not recognize that my test class is a test class. The same test class works fine under test, but does not seem recognized as a test when it is under it.
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class BlackSpec extends AnyFlatSpec with Matchers {
behavior of "Black.adder"
it should "return 42 for any inputs" in {
val six = Black.adder(1, 2)
six shouldBe 42
}
}
When putting the above test under it and executing it from IntelliJ: "Passed: Total 0, Failed 0, Errors 0, Passed 0".
This problem happens in a large (proprietary) project. A minimal example project works fine everywhere, including in IntelliJ: https://gist.github.com/radumanolescu/601b0c743c73b42396b4f6ca9d5fc1db
In the large project, we probably have a setting that disturbs the recognition that my class is an integration test and should be run with ScalaTest. Any idea what that setting might be?

Related

JUnit5 tests work fine with maven but not when run through Eclipse, "No tests found with test runner 'JUnit 5'."

I'm getting a pop-up window with title "Could not run test" and message "No tests found with test runner 'JUnit 5'." when I try to run JUnit 5 tests with Eclipse via Run As > JUnit Test.
I have two test-related files. One is a test suite:
...
import org.junit.jupiter.api.BeforeAll;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.runner.RunWith;
#RunWith(JUnitPlatform.class)
#SelectPackages("com.foo.stufftotest")
public class TestSuite {
#BeforeAll
public static void setup() {
...
The other contains the "actual" tests:
package com.foo.stufftotest;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import com.foo.TestSuite;
import com.foo.business.mechanics.LogicStuff1;
public class BusinessTest {
#Test
public void testLogic1() {
...
}
#Test
public void testLogic2() {
...
}
...
All the testLogicN() methods depend on setup stuff done in TestSuite.setup(). If setup() doesn't run, there are a lot of null values, and it's no surprise that things fail. When I try to run JUnit from the project's context menu, all the tests are triggered and they all fail; the suite doesn't seem to be recognized. When I try to run JUnit specifically from TestSuite.java's context menu, I end up with the error I mentioned at the top of the question.
However, when I run maven test on the project, the suite is triggered properly, and all the tests pass. Therefore, the code itself doesn't seem to be the problem.
I don't remember having this issue with JUnit 4, although I never used JUnit 4 with this particular project.
Am I using Eclipse wrong, or am I using JUnit5 wrong? What's the fix here?
I encountered the same issue in Eclipse Oxygen 4.7.1 despite the fact that my unit tests were properly annotated with org.junit.jupiter.
I used the Maven > Update Project and selected Update project configuration from pom.xml but that did nothing even though I thought it would pick up the fact that I had JUnit5 dependencies in the pom.
My solution:
Open Java Build Path, select Libraries tab and Add Library.
Select JUnit.
Select JUnit5 for JUnit library version.
Once added I was able to manually execute tests from Eclipse. However I'm still not certain why this was not added automatically.
I'm getting a pop-up window with title "Could not run test" and message "No tests found with test runner 'JUnit 5'." when I try to run JUnit 5 tests with Eclipse via Run As > JUnit Test.
That's because TestSuite is in fact not a JUnit 5 test class. Since it is annotated with #RunWith (from JUnit 4) it is a JUnit 4 test class. To avoid the pop-up window in Eclipse, simply click on "Run Configurations" and select JUnit 4 instead of JUnit 5 for running the test class.
The other issue you have is that #BeforeAll is an annotation from JUnit Jupiter. Thus, it is simply not supported in a class annotated with #RunWith(JUnitPlatform.class) (unless that class also happens to contain #Test methods for JUnit Jupiter). Thus you will have to find an alternative approach to executing your "set up" code.

scala test eclipse plugin does not discover test resources

I have a scala project which uses sbt for building/testing/etc. I have a file with unit tests in:
$SBT_PROJECT_ROOT/src/test/scala/foo/bar/SomeSpec.scala
I also have a test resource in:
$SBT_PROJECT_ROOT/src/test/resources/some_test_resource.txt
I attempt to acces this file from the unit tests with:
import org.scalatest._
import scala.io.Source
class TestFiddleParser extends FlatSpec with Matchers {
"This unit test" should "find the test resource" in {
val source = Source.fromURL(getClass.getResource("/some_test_resource.txt"))
val content = source.mkString
println(content.take(1000))
}
}
When I am on the commdand line in the $SBT_PROJECT_ROOT folder and run the command:
sbt test
I can see the first 1000 characters of the test file being printed. Success!
Now I am using eclipse (Scala-IDE) for devolpment. I have eclipse support through sbteclipse (https://github.com/typesafehub/sbteclipse) and I run unit tests from within eclipse using the ScalaTest eclipse plugin (http://www.scalatest.org/user_guide/using_scalatest_with_eclipse).
When I run this unit test from within eclipse, I get a null in the val source. Which I believe means the resource was not found.
What could be the problem?
Ok it was actually quite obvious, just run
sbt eclipse
again AFTER adding the the test resource to the src/test/resources folder.

How do I run test groups with Scala + JUnit runner + Maven?

I'm trying to support running tags/groups of tests on the Maven commandline. I think I have the correct syntax setup in my .scala file (see below), but I'm unsure how to actually execute on the commandline. Examples on the web are mostly in Java.
I want to be able to do something like mvn clean test -Dtags:SlowTest,DbTest to run all the tests tagged as "slow" and "db".
I've seen Surefire pom.xml examples out there, but I'm not sure how I'd then tag the Surefire groups in my test code itself.
Ideas?
import org.junit.experimental.categories.Category
import org.scalatest.FunSuite
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import org.scalatest.Tag
class SlowTest extends Tag("com.mycompany.tags.SlowTest")
class DbTest extends Tag("com.mycompany.tags.DbTest")
#RunWith(classOf[JUnitRunner])
#Category(Array(classOf[SlowTest], classOf[DbTest]))
class FunSuiteTest extends FunSuite with DemoHelpers {
test("DemoTest1") {
If you are using the scalatest-maven-plugin you should be able to do something like this:
mvn -DtagsToInclude=SlowTest,DbTest clean test
I might suggest that if you want to do some test in Scala, why dont you try using
SCALA TEST
it is good and easy to use.

SBT: Plugin dependencies and project classpath

How does one add a external dependency to a SBT plugin and make it available on both the project and plugin classpath ?:
Specifically I have a simple plugin that should run our TestNG test suites and do some post processing. Here is a simplified version:
import sbt._
import java.util.ArrayList
import Keys._
import org.testng._
object RunTestSuitesPlugin extends Plugin {
lazy val runTestSuites = TaskKey[Unit]("run-test-suites", "runs TestNG test suites")
lazy val testSuites = SettingKey[Seq[String]]("test-suites", "list of test suites to run")
class JavaListWrapper[T](val seq: Seq[T]) {
def toJavaList = seq.foldLeft(new java.util.ArrayList[T](seq.size)) { (al, e) => al.add(e); al }
}
implicit def listToJavaList[T](l: Seq[T]) = new JavaListWrapper(l)
def runTestSuitesTask = runTestSuites <<= (target, streams, testSuites) map {
(targetDirectory, taskStream, suites) =>
import taskStream.log
log.info("running test suites: " + suites)
runSuites(suites)
}
private def runSuites(testSuites: Seq[String]) = {
var tester = new TestNG
tester.setTestSuites(testSuites.toJavaList)
tester.run()
}
def testSuiteSettings = {
inConfig(Compile)(Seq(
runTestSuitesTask,
testSuites := Seq("testsuites/mysuite.xml"),
libraryDependencies += "org.testng" % "testng" % "5.14"))
}
}
The problem is that when I add this plugin to a project and run it with run-test-suites then it fails with java.lang.NoClassDefFoundError: org/testng/TestNG even though show full-classpath shows that testng.jar is on the classpath.
So somehow the classpath used when executing the plugin differs from the one in my project, so how do I make a plugin dependency appear in both places ?
I'll try an answer, but I'm not very familiar with the inner details of sbt.
Normally, the path for the build system (as opposed to your program) is under project, as explained here. That would typically be in a project/plugins.sbt. Sounds right, as there is no reason that the application you develop should be concerned by what libraries your build system uses, nor the other way round.
When your plugin run the application code, that may not be so simple and there could well be classpath/classloader issues. I'm not sure that it will work. Normally, your plugin should implement a testing Framework rather than define its own task. Documentation of testing for sbt is limited.
A testing framework should implement org.scalatools.testing.Framework, in test-interface. Your build will take it into account after you add
testFrameworks += new TestFramework("full.class.name")
When you run the normal test command, it let every framework recognize the test classes it deals with (two criteria available: extending some base class or having some annotation) and run them. The framework run in the build, it is given a class loader to access the application code.
You may have a look at the framework implementation for junit (shipped with sbt). Also there is a TestNG implementation. I don't know it, according to its doc, it is a little bit unorthodox, hopefully it will work for you.
The error was fixed by adding TestNG directly to unmanagedJars in Compile in the project that uses the plugin.
I have not found any resources explaining the structure of the SBT class path during plugin execution so any attempt at explaining why this step is necessary will be greatly appreciated.

Run tests in broken project using SBT

When doing a serious refactor in a Java Eclipse project I will often break the build, but focus on getting one test to pass at a time. When running the tests Eclipse warns that the project cannot be compiled, but it will still run the tests it can compile.
Now I'm using SBT and would like to achieve the same thing with 'test-only', but it tries to compile the whole project, fails, and doesn't run the tests. How can I tell it to just compile the bits it can and run the tests.
You should add the following task to your project definition:
import sbt._
class Project(info: ProjectInfo) extends DefaultProject(info) {
lazy val justTest = testTask(testFrameworks, testClasspath, testCompileConditional.analysis, testOptions)
}
This is the same as the ordinary test task, but has no dependencies attached at the end. If you'd like it to have dependencies, call dependsOn on the testTask(...) expression and provide the tasks you want it to depend on.
testTask(testFrameworks, testClasspath, testCompileConditional.analysis, testOptions).dependsOn(testCompile, copyResources, copyTestResources)