Running tests fails (set up problems)

Hi guys

The tests itself are ok (at least most tests).
I have difficulty to run the test (in Netbeans, the option is mostly disabled, IntelliJ has its own special ux, I get not familiar with it). And if I run the test directly, nothing happens. IntelliJ turns back with a message, that test execution failed and no test was found. It seems, that gradle looks for a test for the test.

The repo is here:
https://sourceforge.net/p/jcls/git/ci/master/tree/

Does anybody have an idea, what I did wrong?

In your main.java-common-conventions.gradle you configure the test task to use JUnit Platform, which is JUnit 5.
But you write JUnit 4 tests.
The JUnit platform will not find these tests unless you also add a runtimeOnly dependency on the JUnit Vintage engine, which supports running JUnit 4 tests as JUnit 5 platform.
This makes sense if you also want to use other JUnit 5 platform tests like JUnit Jupiter tests, or - what I strongly recommend - Spock tests.
If you only want to run JUnit 4 tests, use useJUnit() or just leave it out as that is the default anyway.

Hä…why the heck? I have never did anything in the buildSrc directory, but have this line in my build.gradle.kts file:

testImplementation(“junit:junit:4.13”)

I want to keep my JUnit 4 tests. at least for now, as I made them as JUnit 4 was the cutting edge version. Having both versions would be nice for new unit tests, but for now I want to get the old tests running again. What should I do with the buildSrc stuff…as far I know from trying, it is a bad idea to delete it, even I’m sure that Gradle made it up by itself.

What is this?

I have never did anything in the buildSrc directory

That’s probably some example you copied, or default the init plugin generated or similar.
But by not removing it, you configured it like that. :slight_smile:

but have this line in my build.gradle.kts file:

testImplementation(“junit:junit:4.13”)

Which just is a library you add to your test compile classpath.
But by having useJUnitPlatform(), you tell Gradle “I have JUnit Platform tests, so use JUnit Platform to run them”, which then does not find any tests, as you only coded JUnit 4 tests and did not include the vintage engine that would run on the JUnit Platform and run the JUnit 4 tests, as described above. :slight_smile:

I want to keep my JUnit 4 tests. at least for now, as I made them as JUnit 4 was the cutting edge version. Having both versions would be nice for new unit tests, but for now I want to get the old tests running again.

I told you both ways above, either use useJUnit() to only use JUnit 4, or add the vintage engine as runtimeOnly dependency, so that your JUnit 4 tests run through the JUnit Platform.

What should I do with the buildSrc stuff…as far I know from trying, it is a bad idea to delete it

Well, you use it, so it is a bad idea to delete it.
Don’t use it, then you can also delete it.
Or use it properly. :slight_smile:

even I’m sure that Gradle made it up by itself.

Gradle does not make up anything, it just does what you tell it to.
You most probably used the init task and when it asked you, said that you do want to use “multiple subprojects” which you actually do not want, you only have one subproject per build you have, so it does imho not make too much sense. But by answering like that, it also generated the buildSrc with convention plugins where you configure your conventions “how does a java project in this build look like” and similar things and then apply just that convention plugin to all the subprojects (the one you have in your case).

You can read more about convention plugins like these at Sharing Build Logic between Subprojects and about precompiled script plugins as which they are implemented in your case at Developing Custom Gradle Plugins.

What is this?

It is what makes testing fun again. :slight_smile:
https://spockframework.org/spock/docs/2.3/all_in_one.html

Well, I understood that, I just read the manual page to set it up in the way you told me. :wink:

1 Like

Ok, luckily, the gradle documentation provides a whole code snippet to achieve to run legacy tests.
https://docs.gradle.org/current/userguide/java_testing.html#executing_legacy_tests_with_junit_vintage

I just copied the snippet into both, project build.gradle.kts and the groovy file in BuildSrc, just updated the version number to 5.10.0 and wiped the useJunitPlatform() out.

But get the same result as before. Here is the groovy file in BuildSrc (which was generated by Init task, as the comment said, you are right):

plugins {
    // Apply the java Plugin to add support for Java.
    id 'java'
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    constraints {
        // Define dependency versions as constraints
        implementation 'org.apache.commons:commons-text:1.9'
    }

    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
    testCompileOnly 'junit:junit:4.13'
    testRuntimeOnly 'org.junit.vintage:junit-vintage-engine'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
    // Use JUnit Platform for unit tests.
    //useJUnitPlatform()
}

Project build.gradle.kts

plugins {
	java
    id("main.java-application-conventions")
	id("application")
	id("distribution")
	id("org.openjfx.javafxplugin") version "0.1.0"
}

repositories {
	mavenCentral()
}

dependencies {
	testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
    testCompileOnly("junit:junit:4.13")
    testRuntimeOnly("org.junit.vintage:junit-vintage-engine")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
	
	implementation("EngineeringUtils:EngineeringUtils")
	implementation("ForceDeclaredGenerics:ForceDeclaredGenerics")

	annotationProcessor("ForceDeclaredGenerics:ForceDeclaredGenerics")

	implementation("org.apache.commons:commons-collections4:4.4")
	implementation("org.apache.commons:commons-csv:1.9.0")
	implementation("commons-io:commons-io:2.11.0")
	implementation("org.apache.commons:commons-lang3:3.12.0")
	implementation("org.mariuszgromada.math:MathParser.org-mXparser:5.1.0")
	implementation("org.objenesis:objenesis:3.1")
	implementation("org.controlsfx:controlsfx:11.1.0")
}

javafx {
    // sdk = '../libs/JavaFX 16/
	version = "16"
	modules("javafx.controls", "javafx.fxml")
}

application {
	applicationDefaultJvmArgs = listOf(
		"--add-opens=java.base/java.lang=ALL-UNNAMED",
		"--add-opens=java.base/java.util=ALL-UNNAMED",
		"--add-exports=javafx.base/com.sun.javafx.event=ALL-UNNAMED",
		"--add-exports=javafx.controls/com.sun.javafx.scene.control.behavior=ALL-UNNAMED")
	
    // Define the main class for the application.
    mainClass.set("main.Launcher")
}

subprojects {
	apply(plugin = "java")
}

tasks.named("run") {
  tasks.run.get().workingDir = file("$buildDir/dist")
}

tasks.run.configure {
    //workingDir  = ...
		doFirst {
		delete("${rootDir}/Settings.jCLSstg")
		println("${rootDir}/Settings.jCLSstg")
	}
}

distributions {
    main {
        distributionBaseName.set("jCLS")
        //distributionClassifier.set("classifier")
        contents {
            from("../resources/")
        }
    }
}

val run by tasks.existing(JavaExec::class) {
	// dependsOn(tasks.installDist)
	// classpath = files(tasks.installDist.map { "${it.destinationDir}/lib/*" })
	classpath = files(tasks.installDist.map { fileTree("${it.destinationDir}/lib") })
	// mitigate new File('../ressources/') usage
	workingDir(tasks.installDist.map { it.destinationDir })
}

Unfortunately, it does not work, I also tried with the older 5.7.1, but the build stills failing. Or does the double declairing in both files cause any problems?

Edit:
And outcommenting the test stuff in BuildSrc/main.java-common-conversions.gradle does also not change anything.

I just copied the snippet into both, project build.gradle.kts and the groovy file in BuildSrc

But why?
In build.gradle.kts you apply main.java-application-conventions.
In main.java-application-conventions you apply main.java-common-conventions.

So whatever you do in main.java-common-conventions, is the same as when you do it in build.gradle.kts, so doing something in both is just redundant visual clutter.

If you are not happy with convention plugins, especially as you only use them in one project anyway, you should probably just flatten them out and move the content to the applying builds, finally removing the whole buildSrc. That will also save build time in your case as buildSrc does not need to be built first.

wiped the useJunitPlatform()

That’s a pretty bad idea actually.
You copied from an example “how to run JUnit 4 tests on JUnit Platform”, but now removed the configuration to actually use JUnit Platform.
So with removing the useJUnitPlatform() it is useless to depend on the vintage engine, or on Jupiter as those would never run.
By removing the useJUnitPlatform() you are back to the default which is useJUnit() and thus just run plain JUnit 4 tests directly.
Jupiter test would compile, but they will not run just as before the JUnit 4 tests compiled but did not run.

But get the same result as before.
[…]
Unfortunately, it does not work

Then you didn’t do what you state you did.
I cloned current SF state, copied in the two files you showed and it immediately run 550 tests without further change.

but the build stills failing

If it is failing, that is not the same as before.
Before it just did not run any tests, which will only fail in Gradle 9.
Now the build fails, as 21 tests fail due to NullPointerExceptions and InaccessibleObjectExceptions.

Or does the double declairing in both files cause any problems?

No, that is just redundant visual clutter as described above.

1 Like

Hell…there are several ‘Works on my machine’ problems, but ‘Works on your machine and at mine does not’ is just weird.
Maybe I should simply clone my own repo and copy the files in, forgetting that I copied from them as I wrote this… :roll_eyes:

OK, lets get serious, could it be caused by other files which are not compilable? I have a class file ‘a’, and a unit test ‘atest’, and a broken file ‘anytest’, because the class is missing (gone by branch switching).
I would expect, that other unit tests should not effect a test, at least there are not applied. But as I changed from Java 8 to higher version, I remember to get this enerving behavior for a while. But I did not thought that I have it again and hope, I can get the old behavior I know.

I will try to fix it quickly and try the test again, that is the only difference between SF and my local project I see for now.

Hm, seems I misunderstood your post above.

Ok, a quick pseudo fix to satisfy the compiler did it, testing works now.

But is there a way to get test files ‘independent’ from each other? I have no idea why ‘atest’ needs to be compiled if I want to run ‘btest’, and sometimes such conflicts would be enerving.

Not really, unless you split it to multiple test source sets.
The tests as a whole have to compile, that is a prerequisite to run any test.
One class in the tests for example could need other classes in the test sourceset.
This is similar to your other question where you asked whether you can run tests if not all production classes compile which is the same “no”.

Hm…thats a sad de-improvement for me. Get an error during test execution would be better for me, as it works before, but it seems I have to deal with it.

Thanks for your gently help. It’s really good that Gradle works now for me in a productive way. :slight_smile:

If you would use Spock for testing, it would actually a slight bit different,
because then the tests are written in Groovy which is duck-typed.
It still must be valid Groovy syntax in all files and valid Spock syntax.
But if you for example call a method in the production files that does not exist or something similar, it would indeed just fail at runtime.