I'm trying to use scalatest and spark-testing-base on Maven for integration testing Spark. The Spark job reads in a CSV file, validates the results, and inserts the data into a database. I'm trying to test the validation by putting in files of known format and seeing if and how they fail. This particular test just makes sure the validation passes. Unfortunately, scalatest can't find my tests.
Relevant pom plugins:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<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>
<wildcardSuites>com.cainc.data.etl.schema.proficiency</wildcardSuites>
</configuration>
<executions>
<execution>
<id>test</id>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
And here's the test class:
class ProficiencySchemaITest extends FlatSpec with Matchers with SharedSparkContext with BeforeAndAfter {
private var schemaStrategy: SchemaStrategy = _
private var dataReader: DataFrameReader = _
before {
val sqlContext = new SQLContext(sc)
import sqlContext._
import sqlContext.implicits._
val dataInReader = sqlContext.read.format("com.databricks.spark.csv")
.option("header", "true")
.option("nullValue", "")
schemaStrategy = SchemaStrategyChooser("dim_state_test_proficiency")
dataReader = schemaStrategy.applySchema(dataInReader)
}
"Proficiency Validation" should "pass with the CSV file proficiency-valid.csv" in {
val dataIn = dataReader.load("src/test/resources/proficiency-valid.csv")
val valid: Try[DataFrame] = Try(schemaStrategy.validateCsv(dataIn))
valid match {
case Success(v) => ()
case Failure(e) => fail("Validation failed on what should have been a clean file: ", e)
}
}
}
When I run mvn test, it can't find any tests and outputs this message:
[INFO] --- scalatest-maven-plugin:1.0:test (test) # load-csv-into-db ---
[36mDiscovery starting.[0m
[36mDiscovery completed in 54 milliseconds.[0m
[36mRun starting. Expected test count is: 0[0m
[32mDiscoverySuite:[0m
[36mRun completed in 133 milliseconds.[0m
[36mTotal number of tests run: 0[0m
[36mSuites: completed 1, aborted 0[0m
[36mTests: succeeded 0, failed 0, canceled 0, ignored 0, pending 0[0m
[33mNo tests were executed.[0m
UPDATE
By using:
<suites>com.cainc.data.etl.schema.proficiency.ProficiencySchemaITest</suites>
Instead of:
<wildcardSuites>com.cainc.data.etl.schema.proficiency</wildcardSuites>
I can get that one Test to run. Obviously, this is not ideal. It's possible wildcardSuites is broken; I'm going to open a ticket on GitHub and see what happens.
This is probably because there are some space characters in the project path.
Remove space in project path and the tests can be discovered successfully.
Hope this help.
Try excluding junit as a transitive dependency. Works for me. Example below, but note the Scala and Spark versions are specific to my environment.
<dependency>
<groupId>com.holdenkarau</groupId>
<artifactId>spark-testing-base_2.10</artifactId>
<version>1.5.0_0.6.0</version>
<scope>test</scope>
<exclusions>
<!-- junit is not compatible with scalatest -->
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusion>
</dependency>
With me, it's because I wasn't using the following plugin:
<plugin>
<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>
<args>
<arg>-target:jvm-1.8</arg>
</args>
</configuration>
</plugin>
The issue I had with tests not getting discovered came down to the fact that the tests are discovered from the class files, so to make the tests get discovered I need to add <goal>testCompile</goal> to scala-maven-plugin goals.
In my case it's because of the nesting of tests inside the test directory and using the <memberOnlySuites> configuration. <memberonlySuites> only looks out for the test files in the give package / directory. Instead use <wildcardSuites> which will look into a package / directory and all it's subdirectories.
This happens quiet often when you are adding more tests to your test suite and organising them in a more structured manner.
Cause: Maven plugins does not compile your test code whenever you run mvn commands.
Work around:
Run scala tests using your IDE which will compile the test code and saves it in target directory. And when next time you run mvn test or any maven command which internally triggers maven's test cycle it should run the scala tests
Related
I'm trying to get a project that uses gmaven-plugin to compile in Eclipse. When I import the project into Eclipse using the Maven Import I get the error shown below.
After the project finishes importing, I'm left with these Java compile errors (The errors persist if I select one of the MVN profiles):
(The errors persist if I select one of the MVN profiles.)
I’m not sure if the two are related???
I get errors if I try to install this:
http://dist.springsource.org/release/GRECLIPSE/e4.2/
This installs but I still get the same import and compile errors for my project:
https://marketplace.eclipse.org/category/free-tagging/groovy
Snippet from pom.xml is below.
Full project is at
https://github.com/OHDSI/WebAPI
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>add-git-branch-info</id>
<phase>generate-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
if (project.properties.getProperty("git.branch") == null) project.properties.setProperty("git.branch", "*");
if (project.properties.getProperty("git.commit.id.abbrev") == null) project.properties.setProperty("git.commit.id.abbrev", "*");
</source>
</configuration>
</execution>
</executions>
</plugin>
How can these issues be resolved?
When using JMockit with Maven for unit tests, it is required to pass the location of jmockit.jar to the VM by setting the -javaagent parameter. The maven-dependency-plugin can do this automatically, I have set up a configuration that does the expected like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${dependency.plugin.version}</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<argLine>-javaagent:${org.jmockit:jmockit:jar}</argLine>
</configuration>
</plugin>
This works when the test suite and also single tests are called from command line, e.g. by
mvn test -Dtest=MyClass#someTest
From within NetBeans it is also possible to run the whole test suite (e.g. when "Clean and Build" is executed). But when a single file is tested, the path is not injected. There is a command like the following in the log when the VM crashes:
Command was /bin/sh -c cd /home/kap && /usr/lib/jvm/adoptopenjdk-8-hotspot-amd64/jre/bin/java '-javaagent:${org.jmockit:jmockit:jar}' -jar ...
i.e. the placeholder is not filled with the correct location. In contrast, a call on the command line produces
[DEBUG] Forking command line: /bin/sh -c cd /home/kap/ && /usr/lib/jvm/adoptopenjdk-8-hotspot-amd64/jre/bin/java -javaagent:/home/kap/.m2/repository/org/jmockit/jmockit/1.49/jmockit-1.49.jar
It is especially weird that it works with the whole test suite, but not for single tests.
Why does the single test fail?
When executing clean and build NetBeans by default executes mvn clean install. So the maven executes the goal org.apache.maven.plugins:maven-dependency-plugin:properties during its normal build lifecycle and the plugin creates variable ${org.jmockit:jmockit:jar}.
When executing single test file (i.e. Project -> TestFile -> RightClick -> Test File (or Ctl+F6)) NetBeans executes only single goal mvn -Dtest=MyClass#someTest surefire:test. So the maven-dependency-plugin:properties doesn't execute at all and maven could not find the variable ${org.jmockit:jmockit:jar} because it was not been created.
How to solve it?
Option 1.
Go to Project -> Properties -> Actions and for actions Test File set options to execute goal as follows:
test-compile org.apache.maven.plugins:maven-dependency-plugin:properties surefire:test
NetBeans creates the nbactions.xml file so the solution would work only when executing a single test from NetBeans.
Option 2.
Remove maven-dependency-plugin from you pom.xm. Instead specify the location to jmockit.jar using ${settings.localRepository} property:
...
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<jmockit.version>1.43</jmockit.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<argLine>-javaagent:"${settings.localRepository}"/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar</argLine>
</configuration>
</plugin>
</plugins>
</build>
...
Option 3.
I would assume binding the properties goal to the test-compile phase of maven but it would only work if disabling the Compile On Save feature of NetBeans.
...
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>test-compile</phase>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
...
I have the following unit tests:
import org.scalatest.FunSpec
import org.scalatest.Matchers._
class MyClassSpec extends FunSpec {
describe("MyClass"){
describe("Scenario 1"){
it("Condition 1") {
true shouldEqual false
}
it("Condition 2"){
true shouldEqual false
}
}
}
}
When I run maven test, this compiles fine but the tests are not found. Here is the output:
[INFO] --- maven-surefire-plugin:2.7:test (default-test) # project-name ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- scalatest-maven-plugin:1.0:test (test) # project-name ---
Discovery starting.
Discovery completed in 202 milliseconds.
Run starting. Expected test count is: 0
DiscoverySuite:
Run completed in 236 milliseconds.
Total number of tests run: 0
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 0, canceled 0, ignored 0, pending 0
No tests were executed.
As the output shows, I'm using the scalatest plugin for maven. Here is the relevant section of my pom.xml:
<!-- 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}/scalatest-reports</reportsDirectory>
<junitxml>junit</junitxml>
<filereports>report.txt</filereports>
</configuration>
<executions>
<execution>
<id>test</id>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
I'm pretty new to getting this stuff set up, so I'm not sure if there is some other thing I'm not checking. I get the exact same results if I run maven clean and then maven test. I'm using ScalaTest version 3.0.1. I have another project with tests running successfully also using 3.0.1 (I've copied everything I can find between the two projects that seems even remotely related).
You have placed <skipTest> true </skipTest> which is used for skipping the test cases. So basically you have disabled the surefire and it is used for:
The Surefire Plugin is used during the test phase of the build
lifecycle to execute the unit tests of an application. It generates
reports in two different file formats Plain text files (.txt) XML
files (.xml)
Update your pom with:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<useFile>false</useFile>
<disableXmlReport>true</disableXmlReport>
<!-- If you have classpath issue like NoDefClassError,...-->
<!-- useManifestOnlyJar>false</useManifestOnlyJar -->
<includes>
<include>**/*Test.*</include>
<include>**/*Suite.*</include>
<include>**/*Spec.*</include>
</includes>
</configuration>
</plugin>
In include you have to provide the extension of your test file and you can change the version of pluggin.
Thanks
Naturally, the problem seems to have stemmed from some information I didn't think was relevant, so I didn't include it my original post.
The source code I wrote was a tool for unit testing, so I put it in the namespace my.cool.package.testUtilities. The unit tests were thus in my.cool.package.testUtilities.test. Moving the source code out of testUtilities (to just my.cool.package) and moving the tests to just my.cool.package.test allowed the tests to be discovered.
Being new to the java ecosystem (previous experience in .NET), I'm not sure if this is some weird bug with the test runner, expected behavior, or if the act of moving the files to new namespaces did something else, and the namespaces themselves are irrelevant. So I'm not sure what I learned from this.
I have two kinds of tests in my Java (Maven) web project: "normal" unit-tests and integration tests using an embedded Tomcat 7 server and Selenium for automated GUI testing on Jenkins. All tests are annotated with JUnit's #Test, normal tests end with "Test.java" while integration tests end with "IntegrationTest.java". All test-classes are located in src/test/java
I normally build my project with mvn clean verify, while the relevant part of my pom.xml which starts the tomcat server and splits the test-categories accordingly looks like this:
<!-- For front-end testing -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<uriEncoding>UTF-8</uriEncoding>
<additionalConfigFilesDir>${basedir}/conf</additionalConfigFilesDir>
<contextFile>${basedir}/src/test/resources/context.xml</contextFile>
</configuration>
<executions>
<execution>
<id>start-tomcat</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run-war-only</goal>
</goals>
<configuration>
<fork>true</fork>
<port>9090</port>
</configuration>
</execution>
<execution>
<id>stop-tomcat</id>
<phase>post-integration-test</phase>
<goals>
<goal>shutdown</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<excludes>
<exclude>**/*IntegrationTest*</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.16</version>
<configuration>
<includes>
<include>**/*IntegrationTest*</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
This procedure works fine, except when I want to run my tests in eclipse where I normally right-click on my project -> run as -> JUnit Tests. By selecting this option all my tests (including the integration tests) are run. The integration-tests fail in this case because Tomcat is not running (it is only started in Maven's pre-integration-test phase).
How can I exclude these tests in Eclipse with JUnit plugin?
I use junit-toolbox for that. It provides annotations to separate unit and integration tests via wildcard patterns.
<dependency>
<groupId>com.googlecode.junit-toolbox</groupId>
<artifactId>junit-toolbox</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
The base package under e.g. /src/test/java/base contains two classes –
AllUnitTests.java:
package base;
import org.junit.runner.RunWith;
import com.googlecode.junittoolbox.ParallelSuite;
import com.googlecode.junittoolbox.SuiteClasses;
/**
* This detects all (fast running) unit test classes by the given naming pattern.
*
*/
#RunWith(ParallelSuite.class)
#SuiteClasses({ "**/*Test.class", "!**/*IntegrationTest.class", "!**/*LearningTest.class" })
public class AllUnitTests {
}
and
AllIntegrationTests.java:
package base;
import org.junit.runner.RunWith;
import com.googlecode.junittoolbox.SuiteClasses;
import com.googlecode.junittoolbox.WildcardPatternSuite;
/**
* This detects all integration test classes by the given naming pattern.
*
*/
#RunWith(WildcardPatternSuite.class)
#SuiteClasses({ "**/*IntegrationTest.class", "**/*IT.class" })
public class AllIntegrationTests {
}
You can run both generic test suites via Eclipse.
To be able to also run the tests via Maven I use an approach which is similar to the one you have shown.
Im starting to learn scala and mongo , my IDE is intellij IDEA. I created a scala project using
mvn:archetype-generate
and typed a simple hello world program in the IDEA with some arithmetic options such as
println(5)
val i = 1+2
println(i)
Then i compiled it using
mvn compile
It said
build success
But now how should i execute my application and verify the output. There isn't a single article which explains how to start off with scala,maven,idea and i am entirely new to all of this. any help would be useful for me.
maven-exec-plugin
Try with this code:
package com.example
object Main {
def main(args: Array[String]) {
println(5)
val i = 1 + 2
println(i)
}
}
Place it under /src/main/scala/com/example/Main.scala and run it using:
$ mvn package exec:java -Dexec.mainClass=com.example.Main
If you don't want to pass mainClass manually, you can do this in plugin configuration:
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<mainClass>com.example.Main</mainClass>
</configuration>
</plugin>
</plugins>
There are other possibilities, this is the easiest one. Of course in IntelliJ you should be able to run the program directly.
maven-jar-plugin
If you want to ship the application, use maven-jar-plugin to add Main-Class and Class-Path entries to the manifest:
Main-Class: com.example.Main
Class-Path: lib/scala-library-2.9.0-1.jar lib/slf4j-api-1.6.1.jar ...
The following configuration does that and also copies all the dependencies (including Scala runtime library) to target/lib.
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.Main</mainClass>
<addClasspath>true</addClasspath>
<classpathLayoutType>custom</classpathLayoutType>
<customClasspathLayout>lib/$${artifact.artifactId}-$${artifact.version}$${dashClassifier?}.$${artifact.extension}
</customClasspathLayout>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
Now you can simply run your application by (note the target/lib directory is required):
$ java -jar target/your_app-VERSION.jar
You can ship your application simply by copying your JAR file along with /lib subdirectory.
Also see Exec Maven Plugin and Playing with Scala and Maven.