How to make Gradle compile Groovy tests before Java tests - java

The Groovy plugin for Gradle claims that it "supports joint compilation, which allows to freely mix and match Groovy and Java code, with dependencies in both directions".
However, I don't think this applies to test code.
I have a Java 'sample' test in src/test/java... which uses a class which is located in src/test/groovy.
When trying to build with Gradle, I get an error like this:
SwingJavaFXSampleAppTestInJava.java:23: error: cannot find symbol
SwingJavaFXSampleAppTest swingJavaFx = new SwingJavaFXSampleAppTest();
Notice that SwingJavaFXSampleAppTest is a Groovy class that has not been compiled yet (in the Gradle output I can see that it did not run the compileTestGroovy before it tried compileTestJava because the former depends on the latter).
I am able to build this same project with Maven using the groovy-eclipse plugin.
Why does it not work in Gradle when it claims to support compilation in any order, and how can I make it work?

As explained in the Gradle User Guide, only code passed to GroovyCompile tasks is joint-compiled. So either you put both Java and Groovy code into src/main/groovy, or you reconfigure the source sets:
sourceSets.main.java.srcDirs = []
sourceSets.main.groovy.srcDirs = ["src/main/java", "src/main/groovy"]
For tests, replace all occurrences of main with test.

You should be able to move your java tests into src/test/groovy.

Related

How can Junit test classes detect classes defined in a kotlin file?

I have a Java gradle project in which i'm using a kotlin file to easily define pojo-like classes on one line. However, when i try to start a junit5 test I get a compile error stating that it can't detect any of the classes defined in the kotlin file. I have the kotlin plugin included in the gradle.build file. How do i get the test classes to detect the classes defined in the kotlin file?
Thank you
If you write JUnit5-tests with Gradle, be sure to have something like the following in place in your build.gradle-(or build.gradle.kts)-file, so that Gradle also knows that it should use the JUnit5-platform (compare also JUnit 5 User Guide - Build support - Gradle):
tasks.withType<Test> {
useJUnitPlatform()
}
Moreover also ensure that the annotation you use is the following:
org.junit.jupiter.api.Test
and not the one of JUnit4, i.e. org.junit.Test. If you have that one, you probably want to remove the junit4-dependency altogether.

Scala 2.11 -> 2.12 -- Unit test fails in sbt, works in IntelliJ

I have a project that has been working under Scala 2.11, and I'm in the process of upgrading it to use Scala 2.12. I've got a unit test that fails when I run it on the command line through sbt, but it works fine when I run it through IntelliJ IDEA.
The error I get is:
java.lang.NoSuchMethodError: scala.Product.$init$(Lscala/Product;)V
The test is a JUnit test in Java, and it invokes code written in Scala.
The offending line in the unit test:
String paramsJson = adapter.sendReadyMessage();
The sendReadyMessage method (also Java) attempts to create a ReadyMessage:
ReadyMessage rm = new ReadyMessage(timestamp);
And a ReadyMessage is just a Scala case class
case class ReadyMessage(Timestamp: String) extends ToJson
And ToJson is a lift-JSON helper trait that encapsulates JSON generation:
import net.liftweb.json.{DefaultFormats, Serialization}
trait ToJson {
private implicit val formats = DefaultFormats
def toJson = Serialization.write(this)
}
The error appears to happen on the case class ReadyMessage line. The ToJson block is there for context.
Like I said, it works when I run it from within IntelliJ. It fails when I run it under sbt. It fails when it's part of the whole batch of tests in sbt, and it fails when I run it on its own in sbt.
Short of pasting my entire build.sbt file, I'm not sure what other information to include here that might be useful. It seems like it's some kind of version conflict, but I went through and updated all of the software version numbers I can find.
I realize this question covers an issue that may be more complex than can be reasonably debugged over SO. But even a "make sure you've updated XX in your build.sbt" response is helpful.
The answer turned out to be as annoying as the problem itself.
After many hours of searching my build, I realized that there was a "lib" directory in the subproject that was failing. I opened it up, and sure enough, it contained old versions of Scala and some other libs. I deleted those, made sure the libraryDependencies took care of them, and now everything builds and tests just fine.
Thanks to everyone for keeping me on board the "it's a Scala version mismatch" train. And let this be a cautionary tale, kids. Mix your managed and unmanaged dependencies at your own peril.

How to run single Android local unit test using gradle 2.4. Test filtering is not supported

I'm using gradle to build my android project and am not able to run single local unit test. I have several test classes and one of them is MockServerTest and I only want to run test methods in this class.
I tried using gradle -Dtest.single=MockServerTest test but it turned out running all my tests, including these in other test classes.
I also tried gradle test --tests MockServerTest but an error occurred said
Test filtering is not supported for given version of junit. Please upgrade junit version to at least 4.6.
But I'm using junit 4.12 in my gradle file
testCompile 'junit:junit:4.12'
I'm using gradle 2.4 with com.android.tools.build:gradle:1.2.3.
Also, how can I run a single test method inside a single test class?
BTW, I'm able to run single test method inside Android Studio, by right clicking on the test method and select run targetTestMethod() from the menu. But how can I achieve this in the terminal? I guess Android Studio also trigger a certain command to do this. How can I see what that command is?
Figured it out myself. I have to run
gradle testDebug --tests com.my.package.TestClassName
There are two things to note here.
1. You have to use gradle testDebug or gradle testRelease instead of just gradle test. If you have build variant, you have to use gradle testVariantNameDebug or gradle testVariantNameRelease
2. You have to specify the whole qualified class name, means including the package name.
You can use Android Gradle plugin DSL to set up test tasks filters like this:
android {
testOptions {
unitTests.all {
it.testNameIncludePattern = "*.SomeTest"
}
}
}
You can find more information on testOptions here and filters here.
Have you tried running gradle test -Dtest.single=MockServerTest? More information can be found here.

Netbeans groovy code completion not working

I have created a new Gradle project in Netbeans where I want to use java and groovy classes together. To make it work I have configured my build.gradle with the following code:
apply plugin: 'groovy'
sourceSets.main.java.srcDirs = []
sourceSets.main.groovy.srcDir 'src/main/java'
The build process works like a charm: groovy and java classes interoperate transparently. The only annoying thing is the Netbeans code completion. Code completion of java classes does not work from groovy. Let's say I have the following classes:
*my.package1.JavaClass.java
my.package2.GroovyClass.groovy*
From GroovyClass, if I type 'JavaC' and hit CTRL+space the IDE does not present me any help to import and use JavaClass. I have to manually create the import statement. Moreover when I type '.' after the JavaClass instance Netbeans does not show the methods I could call. This happens also for classes included as dependencies.

java mixed with clojure in maven and eclipse

i created a sample polyglot program. i have a sensor and a robot implemented in java and AI implemented in clojure. and i can't connect maven properly
--src/main/java/clojuretest
|
DistanceSensor.java
AI.clj (uses DistanceSensor)
Robot.java (uses AI)
DistanceSensor.java:
package clojuretest;
public class DistanceSensor {
public int getValue() {return 5;}
}
AI.clj:
(ns clojuretest.AI
(:gen-class :methods [[isObstacleAhead [] boolean]]))
(defn -isObstacleAhead [this] (< (.getValue (clojuretest.DistanceSensor.)) 10))
Robot.java:
package clojuretest;
public class Robot {
public boolean shouldStop() {
return new AI().isObstacleAhead();
}
}
i can even manually force maven to compile it:
mvn clean clojure:compile produces error - no DistanceSensor class (but for some reason creates AI.class). so then
mvn compile sees AI.class and compiles everything correctly and tests pass. but what can i do to make mvn clean compile pass? how should my pom.xml look like? also what can i do to make eclipse stop complaining about non existing AI.class?
You need to change layout of source code in your project. Clojure maven plugin requires, that clojure code went to separate directory, so you should have following layout:
src/
main/
java/
java-code
clojure/
clojure code
test/
java/
java tests code
clojure/
clojure tests code
More details you can find in following article
I think :gen-class is usually a code smell, as is trying to instantiate such a class from Java code with new AI().
Here's an alternative approach that can solve this problem of cyclic dependencies:
Define AI as a Java interface in your Java code
Write a Clojure function to create an instance conforming to the interface using reify
Dynamically invoke the Clojure function from Java (e.g. using the technique outlined in this blog post)
You now have an instance of the AI interface that you can use however you like in Java
The advantage is this approach is that everything will work smoothly, in particular:
The Java code base can be compiled independently of the Clojure code
The Clojure code base can access all the defined Java classes and interfaces
You don't need any special IDE / Maven config. In fact, you can treat is as just a regular Java app that happens to include clojure.jar as a dependency.
You have an inter-dependency between Java code and Clojure code. No matter which type of classes you'll compile first, you'll get an error.
Since it's not an actual cyclic dependency, you can still fix this by splitting the Java compilation part in two.
First, compile DistanceSensor, which doesn't depend on anything else.
Second, compile AI, which depends on DistanceSensor.
Finally, compile Robot which depends on AI.
To split the java compilation in two steps, you need to configure the default execution of the maven-compiler-plugin so that it excludes Robot, and add another execution after the clujure:compile goal that excludes DistanceSensor. You'll probably have to misuse the phases to properly order the three executions.

Categories

Resources