getting code coverage for java code with scala tests - scala

The project is a multi module maven project with 90% of the source code written in Java (there's a small bit in Scala). The unit tests are 80/20 java/scala, and the integration tests are 20/80 java/scala.
I tried Clover, but (at this time) it doesn't support scala.
I tried Jacoco. First I ran into problems getting any results due to the mutli-module configuration, but now using Sonar I've got the java coverage shown (thanks http://www.aheritier.net/maven-failsafe-sonar-and-jacoco-are-in-a-boat/). I used timezra (http://timezra.blogspot.com/2013/10/jacoco-and-scala.html) with jacoco, but that only analyzed the small bit of source code that is scala.
I started to try Scoverage, but that seems to have the same problem as timezra (it analyzes scala-to-scala, not the mix that I have). I therefor haven't even tried scct or undercover.
Is there any tool that handles mixed java/scala?

I would suggest to have two separate coverage tools for Java and Scala. More specifically, use Scoverage for Scala (with plugin for Sonar).
The reason is that for Java you would probably like to measure line coverage where for Scala it's much better to measure statement coverage. Simply said because there are many statements on a single line in Scala and you would like to measure which of them were invoked. I've written an article about this.

to answer my own question, Jacoco does analyze coverage for Scala tests and Java code. I haven't seen anything that does the opposite (but we don't have any Java tests for Scala code, so that didn't matter).
As for combining coverage, Rado's answer of using two tools makes sense.
Here's the changes I did to my pom to get coverage. NOTE, I'm creating Jacoco reports when the test runs, then later using Sonar for more analysis:
properties:
<!-- Jacoco and Sonar config properties -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<jacoco.version>0.7.2.201409121644</jacoco.version>
<sonar-jacoco-listeners.version>1.4</sonar-jacoco-listeners.version>
<jacoco.outputDir>${basedir}/target/</jacoco.outputDir>
<jacoco.out.ut.file>jacoco-ut.exec</jacoco.out.ut.file>
<jacoco.out.it.file>jacoco-it.exec</jacoco.out.it.file>
<sonar.jacoco.reportPath>${jacoco.outputDir}/${jacoco.out.ut.file}</sonar.jacoco.reportPath>
<sonar.jacoco.itReportPath>${jacoco.outputDir}/${jacoco.out.it.file}</sonar.jacoco.itReportPath>
Failsafe:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.17</version>
<configuration>
<argLine>-Xms512m -Xmx1024m ${jacoco.agent.it.arg}</argLine>
<properties>
<property>
<name>listener</name>
<value>org.sonar.java.jacoco.JUnitListener</value>
</property>
</properties>
<reportsDirectory>${jacoco.outputDir}/surefire-reports</reportsDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
jacoco:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>prepare-ut-agent</id>
<phase>process-test-classes</phase>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<propertyName>jacoco.agent.ut.arg</propertyName>
<append>true</append>
</configuration>
</execution>
<execution>
<id>prepare-it-agent</id>
<phase>pre-integration-test</phase>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${sonar.jacoco.itReportPath}</destFile>
<propertyName>jacoco.agent.it.arg</propertyName>
<append>true</append>
</configuration>
</execution>
<execution>
<id>default-report</id>
<phase>package</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${sonar.jacoco.reportPath}</dataFile>
</configuration>
</execution>
<execution>
<id>integration-report</id>
<phase>post-integration-test</phase>
<goals>
<goal>report-integration</goal>
</goals>
<configuration>
<dataFile>${sonar.jacoco.itReportPath}</dataFile>
</configuration>
</execution>
</executions>
</plugin>
surefire:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<argLine>${jacoco.agent.ut.arg} -Xms512m -Xmx1024m</argLine>
<skipTests>false</skipTests>
<properties>
<property>
<name>listener</name>
<value>org.sonar.java.jacoco.JUnitListener</value>
</property>
</properties>
<reportsDirectory>${jacoco.outputDir}/surefire-reports</reportsDirectory>
</configuration>
</plugin>
added dependencies:
<dependency>
<groupId>org.codehaus.sonar-plugins.java</groupId>
<artifactId>sonar-jacoco-listeners</artifactId>
<version>${sonar-jacoco-listeners.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.sonar.plugins</groupId>
<artifactId>sonar-surefire-plugin</artifactId>
<version>3.3.2</version>
<scope>test</scope>
</dependency>

It is possible to see the mix of the two languages coverage.
With sonar is not possible, because it only analyzes one kind of language.
If you use jenkins, and configure a step that collect coverage reports(Jacoco), you will see the mixing the two languages.

Related

scala-maven-plugin mixed compile does not include src/main/java and can not find java class

pom.xml:
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<phase>compile</phase>
</execution>
</executions>
</plugin>
<plugin>
<!-- see http://davidb.github.com/scala-maven-plugin -->
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
<configuration>
<args>
<arg>-dependencyfile</arg>
<arg>${project.build.directory}/.scala_dependencies</arg>
</args>
</configuration>
</execution>
</executions>
</plugin>
Code structure:
src/main/java
Hello.java
src/main/scala #will reference the class under /src/main/java
App.scala
IDE : Intellij IDEA 2017.2.1 , JDK: java8
Issues :
when ever i run the maven compile via the intellij, it always show below errors, which means it can not find the Hello.class .
Questions:
why this pom.xml does not work ? I checked the doc of scal-maven-plugin, the layout should work, but it did not .
I found it will work if i add the src/main/java as source directory via the build-helper-maven-plugin. This may explain the first question, but i realized that before the maven compile, i run the App.scala via the Intellij , so the Hello.java has already been compiled to class and i could see it under the src/main/target/classes . So Why the scala-maven-plugin can not find the class under src/main/target/classes ?
like in the documentation/sample linked in the question, remove
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
or set them to src/.../java (the default values), no need to use the build-helper-maven-plugin
or place *.java and *.scala under the same directory (my favorite)
In dual mixed java/scala (scala depends on java and java depends of scala), the scala compiler run against java source, not from binary.
If you want to "notify" the IDE that scala source are under src/.../scala "add"
<goal>add-source</goal>
see add-source

How to pass custom configuration file to Akka application with Maven?

I'm developing an Akka application using Maven. For testing, I use scalatest. When I run the tests with the configuration in application.conf, everything goes smoothly. But when I try to use custom files it just doesn't work (e.g. I have one common.conf and other files that include that one for adjusting time-scale in Jenkins and so on). I tried running the tests with mvn -Dconfig.file=/path/to/myenv.conf test and -Dconfig.resource=/path/to/myenv.conf test but no luck. I'm using Akka 2.4.0 and Scala 2.11.7.
P.S. Here is the configuration of the plugins in my pom.xml:
<build>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>scala-compile</id>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
<configuration>
<args>
<!--arg>-make:transitive</arg-->
<arg>-dependencyfile</arg>
<arg>${project.build.directory}/.scala_dependencies</arg>
</args>
</configuration>
</execution>
</executions>
</plugin>
<!-- disable surefire -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<!-- enable scalatest -->
<plugin>
<groupId>org.scalatest</groupId>
<artifactId>scalatest-maven-plugin</artifactId>
<version>1.0</version>
<configuration>
<reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory>
<stdout>W</stdout>
<!-- Skip coloring output -->
<junitxml>.</junitxml>
</configuration>
<executions>
<execution>
<id>scala-test</id>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Thanks a lot!
Well, I actually found a way, just adding this to my scalatest maven plugin worked:
<argLine>-Dconfig.resource=/local.conf</argLine>
Is there a way to pass this externally to mvn test?

Maven modules will not find dependencies with scalatest

While working with scalatest I ran into a weird problem. I have a maven project with multiple modules. If I execute mvn test directly in the module. It works without problems, but if I do it in the root folder it complains about missing packages (dependencies) while compiling.
My configuration looks like following:
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest_${scala.shortversion}</artifactId>
<version>3.0.0-SNAP2</version>
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest-maven-plugin</artifactId>
<version>1.0</version>
</dependency>
plugin configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.scalatest</groupId>
<artifactId>scalatest-maven-plugin</artifactId>
<version>1.0</version>
<configuration>
<reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory>
<junitxml>.</junitxml>
<filereports>WDF TestSuite.txt</filereports>
</configuration>
<executions>
<execution>
<id>scala-test</id>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
If I remove from maven-scala-plugin the goals it'll compile but scalatest will not find the test sources and exit with No tests were executed.:
<plugin>
<version>2.15.2</version>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<scalaVersion>${scala.version}</scalaVersion>
</configuration>
</plugin>
Any ideas on what I am doing wrong?!
Cheers
Hard to say without seeing all your poms, but generally speaking:
Define in root Pom all your dependencies in dependencyManagement section, your plugins in pluginManagement section with their configuration. In child poms define only those plugins and dependencies you need.
Keep in mind that xxxManagement sections only build shared definition, kind of root configuration. You still have to define in plugins and dependencies sections what you need but you can omit version and configuration elements.
This will allow all your child poms to run tests in all modules.

GWT 2.5.0 mvn install error "Rebind result <class> must be a class"

Problem: I run mvn install on my GWT 2.5.0 project that I built with the gwt-maven-plugin and get the error Rebind result 'c3gw.fwk.gui.client.ClientFactory' must be a class.
This is a snippet of my pom.xml:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>2.5.0</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test</goal>
<goal>i18n</goal>
<goal>resources</goal>
<goal>generateAsync</goal>
</goals>
</execution>
</executions>
<configuration>
<runTarget>C3gwGui.html</runTarget>
<hostedWebapp>${webappDirectory}</hostedWebapp>
<i18nMessagesBundle>c3gw.fwk.gui.client.Messages</i18nMessagesBundle>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
<configuration>
<webappDirectory>${webappDirectory}</webappDirectory>
</configuration>
</plugin>
This is a snippet of my C3gwGui.gwt.xml:
<replace-with class="c3gw.fwk.gui.client.ClientFactoryImpl">
<when-type-is class="c3gw.fwk.gui.client.ClientFactory" />
</replace-with>
This is a snippet of the line where the error is thrown:
public void onModuleLoad() {
ClientFactory clientFactory = GWT.create(ClientFactory.class);
...
}
ClientFactory is an interface and ClientFactoryImpl implements the interface.
What I've figured out so far: The code works perfectly fine in Eclipse when I run debug, it just doesn't work when I do mvn install. I've run all the goals available for gwt-maven-plugin (clean, compile, sources, etc...) and they all work so the only conclusion I can have at this point is that something is happening during the maven-war-plugin phase or much later.
I also took the basics of this code from the following google tutorial and they use an interface so it should work, assuming that the example project also works that is.
Removing war:exploded, as Thomas indicated, solved the issue.

Trouble debugging Maven integration test in Eclipse

I'm using Eclipse Indigo on Win XP, with Maven 3.0.3. I have created a Selenium 2 test that I wish to debug in Eclipse. It is set up to run in the Maven integration test phase. I'm using the Maven Cargo plugin with Tomcat as the container. Here's the relevant section from my pom.xml ...
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<configuration>
<container>
<containerId>tomcat${tomcat.major}x</containerId>
<zipUrlInstaller>
<url>http://archive.apache.org/dist/tomcat/tomcat-${tomcat.major}/v${tomcat.version}/bin/apache-tomcat-${tomcat.version}.tar.gz</url>
<downloadDir>${project.build.directory}/downloads</downloadDir>
<extractDir>${project.build.directory}/extracts</extractDir>
</zipUrlInstaller>
<output>${project.build.directory}/tomcat${tomcat.major}x.log</output>
<log>${project.build.directory}/cargo.log</log>
</container>
<configuration>
<home>${project.build.directory}/tomcat-${tomcat.version}/container</home>
<properties>
<cargo.logging>high</cargo.logging>
<cargo.servlet.port>8080</cargo.servlet.port>
</properties>
</configuration>
</configuration>
<executions>
<execution>
<id>start-container</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
<goal>deploy</goal>
</goals>
<configuration>
<deployer>
<deployables>
<deployable>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<type>war</type>
<pingURL>http://localhost:8080/${project.artifactId}</pingURL>
<pingTimeout>30000</pingTimeout>
<properties>
<context>${project.artifactId}</context>
</properties>
</deployable>
</deployables>
</deployer>
</configuration>
</execution>
<execution>
<id>stop-container</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- Skip the normal tests, we'll run them in the integration-test phase -->
<skip>true</skip>
</configuration>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>false</skip>
</configuration>
</execution>
</executions>
</plugin>
Problem is, when I right click on my integration test in Eclipse, select "Debug As" and then choose my Debug Configuration (which is just the maven goal "clean install -Dtest=TableIntegrationTest"), the execution runs without hitting the breakpoint I set (http://screencast.com/t/at0AKWwxslE). How can I do step-through debugging on a JUnit/Selenium integration test in Eclipse?
Maven's integration tests by default run in a forked JVM. Therefore, eclipse is unable to attach to the forked JVM and see the breakpoints.
You can force the integration-test to run in the same JVM with the -DforkMode=never option.
More here: http://maven.apache.org/surefire/maven-surefire-plugin/examples/fork-options-and-parallel-execution.html
Edit: Updated link