Run tests in broken project using SBT - scala

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)

Related

Scala sbt tests: "No configuration setting found for key 'akka'" after switching to Java 11

After switching to Java 11, sbt tests started to fail with the exception "No configuration setting found for key 'akka'". We are using sbt assembly plugin on the project but since the tests are run not inside jar but using sbt <module_name>/test, looks like there are some issues with building test resources/paths.
List of things I did:
Added concat MergeStrategy for 'reference.conf' file. Jar that is assembled has all files inside and there are no issues with that, so it is only a test step issue.
Checked class path for tests using 'export <module_name>/test:fullClasspath' in sbt before and after migrating to Java 11. They are the same.
Everything else except of a test where I create actor system works good.
Code that creates actor system:
object MyObjectTest extends AsyncFunSuite {
private implicit val system: ActorSystem = ActorSystem("MyActorSystem")
private implicit val ex: ExecutionContext = system.dispatcher
}
At the moment I do not have any ideas what should I check next, so any suggestions would be appreciated.
P.S. running tests inside IDEA works good, but we have CI/CD job that runs tests using sbt test command.
I guess there are some issues when you are using sbt + Java 11. I tried to reproduce this error using a small project with the same configuration but was not been able to do it. However, the issue was fixed using the following option in sbt:
Test / fork := true
According to sbt documentation, this property creates a separate JVM for running all tests. I think all configurations have been set up correctly for another JVM.
Hope this answer will help someone in future.

SBT - ignore compile errors (in tests)?

in my current SBT project test:compile reports all errors, but does not generate class files for the valid and unrelated tests.
It would be useful to run these tests separately.
Is it possible to force SBT to generate all class files it can?

how to use JUNIT using makefile?

I am very new to JUNIT. I have Makefile to compile my code and which will generate a jar file and now I want to run my JUNIT test case for that.
I not sure how to find out .class file using JAR. I am using LINUX as I know I need a .class file to execute a JUNIT case.
can some one help me?
from http://c2.com/cgi/wiki?UnitTestCookbooks:
I use JavaUnit for my unit tests. For a class Foo, its source is in
Foo.java. Its unit test lives in a separate class, with the source in
TestFoo.java. A command line invokes the unit test, in either console
mode or with a GUI. I use the console mode tester:
java junit.textui.TestRunner TestFoo
I build an "all-in-one" test suite for a package, which runs all of
the unit tests in the package. It's called TestAll. This is usually
the test I run when working on the package.
I add a rule like this to my makefile:
test: TestAll.class
java junit.textui.TestRunner TestAll
when I run "make test", Test'All.class gets built (through another
rule) and then junit is run with the standard command-line.

How to compile tests with SBT without running them

Is there a way to build tests with SBT without running them?
My own use case is to run static analysis on the test code by using a scalac plugin. Another possible use case is to run some or all of the test code using a separate runner than the one built into SBT.
Ideally there would be a solution to this problem that applies to any SBT project. For example, Maven has a test-compile command that can be used just to compile the tests without running them. It would be great if SBT had the same thing.
Less ideal, but still very helpful, would be solutions that involve modifying the project's build files.
Just use the Test / compile command.
Test/compile works for compiling your unit tests.
To compile integration tests you can use IntegrationTest/compile.
Another hint to continuously compile on every file change: ~Test/compile
We have a build.sbt file that is used for multiple projects. Doing sbt test:compile compiled the tests for every single project and took over 30 minutes.
I found out I can compile only the tests for a specific project named xyz by doing:
sbt xyz/test:compile
Using sbt version 1.5.0 and higher test:compile returns deprecation warning.
Use Test / compile.
(docs)

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.