I've got a mixed Java / Scala project with both JUnit and ScalaTest tests. With the scalatest plugin, Gradle runs the ScalaTest tests in src/test/scala, but ignores the JUnit tests in src/test/java. Without the plugin, Gradle runs the JUnit tests but ignores the Scala. What trick am I missing?
My build.gradle:
plugins {
id 'java'
id 'maven'
id 'scala'
id "com.github.maiflai.scalatest" version "0.6-5-g9065d91"
}
sourceCompatibility = 1.8
group = 'org.chrononaut'
version = '1.0-SNAPSHOT'
task wrapper(type: Wrapper) {
gradleVersion = '2.3'
}
ext {
scalaMajorVersion = '2.11'
scalaVersion = "${scalaMajorVersion}.5"
}
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
compile "org.scala-lang:scala-library:${scalaVersion}"
compile "org.scala-lang.modules:scala-xml_${scalaMajorVersion}:1.0.3"
compile 'com.google.guava:guava:18.0'
compile 'javax.xml.bind:jaxb-api:2.2.12'
compile 'jaxen:jaxen:1.1.6'
compile 'joda-time:joda-time:2.7'
compile 'org.joda:joda-convert:1.7'
compile 'org.apache.commons:commons-lang3:3.3.2'
compile 'org.jdom:jdom2:2.0.5'
testCompile 'junit:junit:4.12'
testCompile 'org.easytesting:fest-assert:1.4'
testCompile 'org.mockito:mockito-core:1.10.19'
testCompile "org.scalatest:scalatest_${scalaMajorVersion}:2.2.4"
testRuntime 'org.pegdown:pegdown:1.1.0' // required by scalatest plugin
}
compileScala {
scalaCompileOptions.additionalParameters = [
"-feature",
"-language:reflectiveCalls", // used for config structural typing
"-language:postfixOps"
]
}
ETA: I know it's possible to annotate Scala tests to force them to run with the JUnit test runner. I'm looking for a one-stop build.gradle solution that doesn't require editing every test file (or messing with the tests to get around limitations in the build system, in general).
Another alternative to running with JUnit (and to creating an Ant task as suggested in comments) - is creating a task that runs ScalaTest's Runner directly:
task scalaTest(dependsOn: ['testClasses'], type: JavaExec) {
main = 'org.scalatest.tools.Runner'
args = ['-R', 'build/classes/test', '-o']
classpath = sourceSets.test.runtimeClasspath
}
test.dependsOn scalaTest // so that running "test" would run this first, then the JUnit tests
Get rid of the plugin, as it makes test task to run ScalaTest only (so JUnit gets ignored).
Annotate your ScalaTests with #RunWith(classOf[JUnitRunner])so they can be run by gradle as JUnit tests.
With the latest version of scala-test plugin you can choose whether the existing (junit)-test task is replaced or not by the scala-tests-task. In your case you could use the following in
gradle.properties:
com.github.maiflai.gradle-scalatest.mode = append
Now you can execute both tests:
junit: gradle test
scala-test: gradle scalatest
or combine them into one task
task allTests {
dependsOn test
dependsOn scalatest
}
That worked for me.
There is an easier solution these days.
You can just specify multiple junit test engines in useJUnitPlatform using scalatest-junit-runner for scala:
dependencies {
// junit platform
testRuntimeOnly("org.junit.platform:junit-platform-engine")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
// junit5 engine
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
// junit4 engine
testRuntimeOnly("org.junit.vintage:junit-vintage-engine")
// scalatest engine
testRuntimeOnly("co.helmethair:scalatest-junit-runner")
}
test {
useJUnitPlatform {
includeEngines "junit-jupiter", "junit-vintage", "scalatest"
testLogging {
events("passed", "skipped", "failed")
}
}
}
You can even implement your own similar to ScalatestEngine this library provides.
One more useful link https://github.com/junit-team/junit5-samples/blob/main/junit5-migration-gradle/README.md
Related
I know this is "common" error but I am trying to make a JUnit5 Android Room test working.
I found out that JUnit5 does not support the instrumentation test (or google does not support JUnit 5 I should say) but I discovered that https://github.com/mannodermaus/android-junit5 is supposed to help me.
I modified my graddle to have the plugin added in my module and the classpath at the top of the project.
classpath("de.mannodermaus.gradle.plugins:android-junit5:1.7.1.1")
id("kotlin-android")
I also added the specific dependencies from it
androidTestImplementation("de.mannodermaus.junit5:android-test-core:1.2.2")
androidTestRuntimeOnly("de.mannodermaus.junit5:android-test-runner:1.2.2")
And in the android defaultConfig of my module I added
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArgument("runnerBuilder", "de.mannodermaus.junit5.AndroidJUnit5Builder")
The graddle builds fine but the issue is when I run my simple test
class DbTest
{
private lateinit var myDao : MyDao
#BeforeEach
fun init()
{
val context : Context = ApplicationProvider.getApplicationContext();
val db = Room.inMemoryDatabaseBuilder(
context,
ConfigDatabase::class.java).build()
tcdDao = db.getMyDao()
}
[...]
}
The error occurs when I get the context :
No instrumentation registered! Must run under a registering instrumentation.
I want to specify that I cannot use JUnit4.
Am I missing something ? Can I actually test my database with JUnit5 ? Or should I use another solution ?
So I've been trying to run the libGDX command "gradlew html:superDev" for my project but it always gives me and error part way through the process:
> Task :html:beforeRun FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':html:beforeRun'.
> Could not resolve all files for configuration ':html:grettyRunnerJetty94'.
> Could not find org.gretty:gretty-runner-jetty94:3.0.2.
Searched in the following locations:
- file:/C:/Users/Joachim/.m2/repository/org/gretty/gretty-runner-jetty94/3.0.2/gretty-runner-jetty94-3.0.2.pom
- https://repo.maven.apache.org/maven2/org/gretty/gretty-runner-jetty94/3.0.2/gretty-runner-jetty94-3.0.2.pom
- https://dl.google.com/dl/android/maven2/org/gretty/gretty-runner-jetty94/3.0.2/gretty-runner-jetty94-3.0.2.pom
- https://oss.sonatype.org/content/repositories/snapshots/org/gretty/gretty-runner-jetty94/3.0.2/gretty-runner-jetty94-3.0.2.pom
- https://oss.sonatype.org/content/repositories/releases/org/gretty/gretty-runner-jetty94/3.0.2/gretty-runner-jetty94-3.0.2.pom
Required by:
project :html
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.7.1/userguide/command_line_interface.html#sec:command_line_warnings
This is what the build.gradle file looks like (the one located in the project folder):
buildscript {
repositories {
gradlePluginPortal()
mavenLocal()
mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
google()
}
dependencies {
classpath 'org.wisepersist:gwt-gradle-plugin:1.0.13'
classpath 'org.gretty:gretty:3.0.3'
}
}
allprojects {
apply plugin: "eclipse"
version = '1.0'
ext {
appName = "ludum-dare-48"
gdxVersion = '1.9.14'
roboVMVersion = '2.3.12'
box2DLightsVersion = '1.5'
ashleyVersion = '1.7.3'
aiVersion = '1.8.2'
gdxControllersVersion = '2.1.0'
}
repositories {
gradlePluginPortal()
mavenLocal()
mavenCentral()
google()
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven { url "https://oss.sonatype.org/content/repositories/releases/" }
}
}
project(":desktop") {
apply plugin: "java-library"
dependencies {
implementation project(":core")
api "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion"
api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
}
}
project(":html") {
apply plugin: "java-library"
apply plugin: "gwt"
apply plugin: "war"
apply plugin: "org.gretty"
dependencies {
implementation project(":core")
api "com.badlogicgames.gdx:gdx-backend-gwt:$gdxVersion"
api "com.badlogicgames.gdx:gdx:$gdxVersion:sources"
api "com.badlogicgames.gdx:gdx-backend-gwt:$gdxVersion:sources"
api "com.badlogicgames.box2dlights:box2dlights:$box2DLightsVersion:sources"
}
}
project(":core") {
apply plugin: "java-library"
dependencies {
api "com.badlogicgames.gdx:gdx:$gdxVersion"
api "com.badlogicgames.box2dlights:box2dlights:$box2DLightsVersion"
}
}
Any help in fixing this problem would be very much appreciated. Thanks!
In the maven reposotories it seems that there is no such version 3.0.2 of the project you are looking for. Maybe it got deleted and replaced by version 3.0.3.
So a solution would be to check your build.gradle file (probably the one in the html project) and replace the string org.gretty:gretty-runner-jetty94:3.0.2 by either org.gretty:gretty-runner-jetty94:3.0.3 or org.gretty:gretty-runner-jetty94:2.3.0.
You should try version 3.0.3 first, since 2.3.0 might be lacking some features.
Ok so I went to my main gradle.build file and in the repositories {} block for both the buildscript {} block and the allprojects {} block I put gradlePluginPortal() and now the superDev command works fine.
I'm trying to run my unit tests through mpirun using ant. I have specified the task as:
<target name="unitTest" depends="buildUnitTest">
<mkdir dir="reports"/>
<junit fork="yes" jvm="mpirun java" printsummary="yes" haltonfailure="yes">
<classpath>
<pathelement location="./bin"/>
<pathelement location="/usr/share/java/junit4.jar"/>
</classpath>
<jvmarg value="-DDIM=3"/>
<jvmarg value="-ea"/>
<formatter type="plain"/>
<batchtest todir="reports">
<fileset dir="test">
<include name="haparanda/utils/*Test.java"/>
<include name="haparanda/iterators/*Test.java"/>
<exclude name="haparanda/iterators/FieldIteratorTest.java"/>
<include name="haparanda/grid/*Test.java"/>
</fileset>
</batchtest>
</junit>
</target>
Running eg:
mpirun java -ea -DDIM=3 -cp ./bin:/usr/share/java/junit4.jar org.junit.runner.JUnitCore haparanda.grid.ComputationalComposedBlockTest
from command line works fine. However, when I run:
ant unitTest
I get the following error:
BUILD FAILED
.../build.xml:28: Process fork failed.
Running ant with the verbose flag I get told that I got an IOException with the error message:
Cannot run program "mpirun java": error=2, No such file or directory
This is the case also when I specify the full path to mpirun and Java:
<junit fork="yes" jvm="/home/malin/bin/openmpi/bin/mpirun /usr/bin/java" printsummary="yes" haltonfailure="yes">
gives me:
.../build.xml:28: Process fork failed.
at ...
Caused by: java.io.IOException: Cannot run program "/home/malin/bin/openmpi/bin/mpirun /usr/bin/java": error=2, No such file or directory
How can i make this work?
This question is quite old and seems to have been successfully addressed in the comments by Gilles Gouaillardet. In the academic setting I am working in, I also attempted to use Junit with Java and MPI. I was unable to successfully use the trick proposed by Gilles Gouaillardet and I ended up with a quite different solution.
Custom Junit4 runner - general idea
An other way of running Junit tests with MPI consists in implementing a custom Junit runner.
In this custom Junit runner, instead of calling the Test methods "directly", you can launch your custom command using a ProcessLauncher. In my implementation, I made every MPI process use the normal Junit4 runtime to run the test methods. However, instead of using the normal RunNotifier of the Junit runtime, the MPI processes use my custom RunNotifier which writes the calls it receives to a file. A file with the calls of
Back in my custom runner, once the mpirun processes have finished, I aggregate the results of each test method of each MPI process and transmit those to the normal RunNotifier.
Benefits
With this system, you are staying within the "normal" Junit4 framework. In my case I was trying to run Junit tests from Maven. I can also integrate the test results with the Eclipse Junit view successfully (this required a few tricks that are not shown in the code excerpt below).
Here is a capture of my Eclipse environment after running the tests (the class names are slightly different than those presented in the excerpts below due to some additional complications for my particular environment).
Some selected code details
Only the most important parts of the custom MpiRunner and MpiTestLauncher are shown. Imports, try/catch structures and numerous details have been removed. I will eventually make the whole code available on GitHub but it isn't quite ready yet.
/** A test class using the custom "MpiRunner" */
#RunWith(MpiRunner.class)
public class TestUsingMpi {
#Test
public void test() {
assertTrue("Should run with multiple processes", MPI.COMM_WORLD.Size() > 1);
}
}
/** Curstom Junit4 Runner */
public class MpiRunner extends Runner {
// some methods skipped, try/catch blocks have been removed
#Override
public void run(RunNotifier notifier) {
// Build the command
final ArrayList<String> command = new ArrayList<>();
command.add("mpirun");
command.add("-np");
command.add(String.valueOf(processCount));
command.add("java");
// Classpath, UserDirectory, JavaLibraryPath ...
command.add("MpiTestLauncher "); // Class with main
command.add(testClass.getCanonicalName()); // Class under test as argument
ProcessBuilder pb = new ProcessBuilder(command);
File mpirunOutFile = new File("MpirunCommandOutput.txt");
pb.redirectOutput(Redirect.appendTo(mpirunOutFile));
pb.redirectError(Redirect.appendTo(mpirunOutFile));
Process p = pb.start(); // Launch the mpirun command
p.waitFor(); // Wait for termination
// Parse the notifications of each MPI process
for (int i = o; i < NbProcesses; i++) {
List<Notification> mpiRankNotifs = parse(i);
//Re-run those notifications on the parameter "notifier" of this method
for (Notification n : notifications) {
//Reconstitute the method call made in the mpi process
Class<?> paramClass = n.parameters[0].getClass();
Method m = RunNotifier.class.getDeclaredMethod(n.method, paramClass);
m.invoke(notifier, n.parameters);
}
}
}
}
/** Main class of the Mpirun java processes */
public class MpiTestLauncher {
public static void main(String[] args) throws Exception {
MPI.Init(args);
commRank = MPI.COMM_WORLD.Rank();
commSize = MPI.COMM_WORLD.Size();
Class<?> testClass = Class.forName(args[0]); // Class that contains the tests
String notificationFileName = testClass.getCanonicalName() + "_" +
commRank;
File f = new File(notificationFileName);
CustomNotifier notifier = new MpiApgasRunNotifier(f);
BlockJUnit4ClassRunner junitDefaultRunner = new BlockJUnit4ClassRunner(testClass);
junitDefaultRunner.run(notifier);
notifier.close(); //Flushes the underlying buffer
MPI.Finalize();
}
}
I have working code which uses JSON with package shown below.
import com.google.appengine.labs.repackaged.org.json.JSONException;
import com.google.appengine.labs.repackaged.org.json.JSONObject;
Code runs in app engine, built under eclipse. And now I'm trying to migrate it to Android Studio. But I can't find out how to refer correct library with it, so I can't compile. My current build.gradle file is shown below.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.google.appengine:gradle-appengine-plugin:1.9.18'
}
}
repositories {
jcenter();
}
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'appengine'
war.dependsOn appengineEnhance
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
dependencies {
appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.18'
compile 'com.google.appengine:appengine-endpoints:1.9.18'
compile 'com.google.appengine:appengine-endpoints-deps:1.9.18'
compile 'com.google.appengine.orm:datanucleus-appengine:2.1.2'
compile 'javax.servlet:servlet-api:2.5'
compile 'javax.jdo:jdo2-api:2.3-eb'
compile 'org.datanucleus:datanucleus-api-jdo:3.1.3'
}
appengine {
downloadSdk = true
appcfg {
oauth2 = true
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
enhancer {
version = "v2"
api="jdo"
enhanceOnBuild = true
}
}
There are other libraries I need to add but I want to fix this issue first.
I found a solution. Adding next line to build.gradle made successful compile.
compile 'com.google.appengine:appengine-api-labs:1.7.4'
Now I can go forward to run/debug server side code.
We use JUnit as a test framework. We have many projects. We use gradle (version 1.12) as a build tool. To run the unit tests in parallel using gradle we use the below script in every project under test task.
maxParallelForks = Runtime.runtime.availableProcessors()
Ex:
test {
maxParallelForks = Runtime.runtime.availableProcessors()
}
We also maintain the single gradle.properties file.
Is it possible to define test.maxParallelForks = Runtime.runtime.availableProcessors() in gradle.properties file rather than defining it in each build.gradle file under test task?
The accepted answer above works but the Gradle documentation here suggests you use
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
I tried both and after testing both on a 2.3 GHz Intel Core i7 Mac Book Pro with 16GB RAM (4 cores with hyperthreading)
test {
maxParallelForks = Runtime.runtime.availableProcessors()
}
and
test {
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
}
The approach suggested by Gradle documentation produced faster response times for our unit test suite: 7 minutes vs. 8 minutes (compared to the original 13 minutes). In addition my Mac CPU didn't get pegged and the fan didn't kick off.
I assume there is either contention on a shared resource - even if it is only the machine one which we are running the unit tests.
$rootDir/build.gradle:
subprojects {
tasks.withType(Test) {
maxParallelForks = Runtime.runtime.availableProcessors()
}
}
For those of us using Gradle Kotlin DSL in a build.gralde.kts who find themselves here after a google search, I was able to get it to work this way:
tasks.test {
maxParallelForks = Runtime.getRuntime().availableProcessors()
}
or
tasks.withType<Test> {
maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1
}
as I found here
edit: I ran into some issue as described here. This is (hopefully) my final form:
tasks.withType<Test> {
systemProperties["junit.jupiter.execution.parallel.enabled"] = true
systemProperties["junit.jupiter.execution.parallel.mode.default"] = "concurrent"
maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1
}
kotlin gradle dsl
tasks.withType<Test> {
maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1).also {
println("Setting maxParallelForks to $it")
}
}