Maven: obtain path to output JAR from integration test - java

I want to write an E2E test for a Maven project. The flow would be to run the resulting JAR and verify it's output. The question is how can I obtain the path to the output JAR from an integration test (written in JUnit run by the Failsafe plugin).

You can either use command line or make an entry in pom.xml to tell where you want jar file saved.
on command line
-DoutputDirectory=<specify_your_path>
On in your pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>x.y.z</version>
<configuration>
<outputDirectory>/your/path/for/jar</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
Now on how to read path in test : The unit test will still run even if not using Maven, the target directory will still get created two dirs up relative to the current working directory of wherever the tests are run. You can use the method below to get the target directory in test.
public File targetDir(){
String relPath = getClass().getProtectionDomain().getCodeSource().getLocation().getFile();
File targetDir = new File(relPath+"../../target");
if(!targetDir.exists()) {
targetDir.mkdir();
}
return targetDir;
}

Related

Is it possible to run only the failed test in junit cucumber framework when i explicitly declare feature file in command line?

I build a Jenkins pipeline where i execute my cucumber tests.
I have configured in pom xml 2 runners in surefire plugin for 1st run and rerun execution like this
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<runOrder>alphabetical</runOrder>
<includes>
<include>**/*TestRunner.java</include>
</includes>
</configuration>
</plugin>
pretty straight forward!!!
Here is AllTestRunner.java
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"classpath:com/bdd/jenkins/migrated"}, //classpath special variable referes refers to src/test/resources path
glue = {"com.bdd.helpers", "com.bdd.steps"},
tags= "not #Fail and not #ignore", //not #ignore
plugin = {"pretty", "html:cucumber-reports/cucumber", "json:cucumber-reports/cucumber.json", "rerun:target/rerun.txt"}
)
public class AllTestRunner {
}
And here is my **FailTestRunner.java **
#CucumberOptions(
features = {"#target/rerun.txt"}, //classpath special variable refers to src/test/resources path
glue = {"com.bdd.helpers", "com.bdd.steps"},
tags= "not #Fail and not #ignore", //not #ignore
plugin = {"pretty", "html:cucumber-reports/cucumber_rerun", "json:cucumber-reports/cucumber_rerun.json"}
)
public class FailTestRunner {
}
The problem is that if i want to run ad-hoc a specific feature file via command line, e.g
mvn clean test -Dcucumber.features="test.feature"
the FailTestRunner.java execute again all the scenarios that test.feature file has, because command line argument override the feature param.
Is possible with this pom.xml, and configuration overall, to have a jenkins job, with run and rerun phase? or i have to change approach and thinking sth else?
e.g like creating a separate rerun job that would take somehow the rerun file
Thank you

How to create .bat files using Maven Appassembler that runs a JAR?

I'm trying to create a .bat file to run my generated executable JAR file. I found this method of creating .bat files for running a project. So, I read up on the plugin here and added the following to my pom.xml.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
<configuration>
<assembleDirectory>${assembleDir}</assembleDirectory>
<generateRepository>false</generateRepository>
<repositoryName>lib</repositoryName>
<configurationDirectory>conf</configurationDirectory>
<copyConfigurationDirectory>false</copyConfigurationDirectory>
<programs>
<program>
<mainClass>com.companyname.tests.TestRunner</mainClass>
<id>AutoConfigTest</id>
</program>
</programs>
</configuration>
</plugin>
And, yes, as the name suggests, this JAR contains JUnit test cases.
I prevented the plugin from unpacking JARs and creating the repo folder and set that to my already generated lib folder, which contains all the JARs(executables and the dependencies). The .bat file is being generated but, when running it, I'm getting the following error.
Error: Could not find or load main class com.companyname.tests.TestRunner
Also, I want the command prompt to stay after execution. In this case it is closing immediately. Maybe its because I'm getting an error. I'm not sure.
So, got into searching again and found this. But as the accepted answer suggests, my pom.xml already contains -
<packaging>jar</packaging>
The assembled directory is -
AutoConfigTest
|
|--bin
| `- contains the .bat file
|--conf
| `- contains the property files and other configuration files
|--lib
`- contains all the JARs
What am I doing wrong here?
Maybe it's related to (from the README.md)
All dependencies and the artifact of the project itself are placed in a generated Maven repository in a defined assemble directory. All artifacts (dependencies + the artifact from the project) are added to the classpath in the generated bin scripts.
In your pom.xml you prevent the generation of that repository. So you need to ensure that the artifact from the project is copied at the expected place.
Assuming following project settings
<groupId>com.companyname</groupId>
<artifactId>Maven-AppAssembler</artifactId>
<version>0.0.1-SNAPSHOT</version>
the artifact is expected to be at (the CLASSPATH setting in the scripts bin/AutoConfigTest)
"$REPO"/com/companyname/Maven-AppAssembler/0.0.1-SNAPSHOT/Maven-AppAssembler-0.0.1-SNAPSHOT.jar
where $REPO resolve to target/appassembler/lib.
I found the issue. #SubOptimal was correct in pointing out that the main class isn't visible to the batch file.
For some reason, the test JAR file (which contains the main class) isn't being added to the classpath variable of the batch file. As a result, whenever I ran the batch file, I was getting the error mentioned in the question.
I went back to the documentation and found this.
Sometimes it happens that you have many dependencies which means having a very long classpath, and becomes too long (in particular on Windows based platforms). This option can help in such situation. If you activate this option, your classpath contains only a classpath wildcard (REPO/*). But be aware that this works only in combination with Java 1.6 and above and with repositoryLayout flat.
So, instead of adding individual JAR files into the path, I added the whole lib directory to the classpath by adding the following to the pom.xml.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.10</version>
...
<configuration>
...
<repositoryLayout>flat</repositoryLayout>
<useWildcardClassPath>true</useWildcardClassPath>
...
</configuration>
...
</plugin>
I could do this because the repository layout of lib was already flat. There were no hierarchies. No other change was required. The batch file now behaves as expected.

gradle to maven plugin conversion

How can I write equivalent maven plugin for the following gradle plugin defined?
/*
* Plugin to copy system properties from gradle JVM to testing JVM
* Code was copied from gradle discussion froum:
* http://forums.gradle.org/gradle/topics/passing_system_properties_to_test_task
*/
class SystemPropertiesMappingPlugin implements Plugin{
public void apply(Project project){
project.tasks.withType(Test){ testTask ->
testTask.ext.mappedSystemProperties = []
doFirst{
mappedSystemProperties.each{mappedPropertyKey ->
def systemPropertyValue = System.getProperty(mappedPropertyKey)
if(systemPropertyValue){
testTask.systemProperty(mappedPropertyKey, systemPropertyValue)
}
}
}
}
}
}
It really depends on what exactly you want to achieve.
In case you want to help with writing a maven plugin in general, you'll have to read the documentation.
In case you want to filter system properties that Maven JVM passes to your test JVM, I don't see any other option than extending the maven-surefire-plugin plugin and add there an option to do such mapping. (Note that by default Maven passes all its System Properties to the test JVM.) That is definitely doable but maybe you can achieve your goal with something maven already offers.
You can definitely pass additional system properties to your test JVM from Maven by using:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<systemPropertyVariables>
<propertyName>propertyValue</propertyName>
<anotherProperty>${myMavenProperty}</buildDirectory>
</systemPropertyVariables>
</configuration>
</plugin>
as documented http://maven.apache.org/surefire/maven-surefire-plugin/examples/system-properties.html.
In this case you can set the value of anotherProperty from command line by invoking maven
mvn test -DmyMavenProperty=theValueThatWillBePassedToTheTestJVMAsProperty_anotherProperty
You can also use Surefire argline to pass multiple properties to the JVM. For instance
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<argLine>${propertiesIWantToSetFromMvnCommandLine}</argLine>
</configuration>
</plugin>
and execute maven as follows
mvn test -DpropertiesIWantToSetFromMvnCommandLine="-Dfoo=bar -Dhello=ahoy"
in this case, you'll see properties foo and hello with values bar and ahoy, respectively, in your test JVM.

executable jar for selenium testng maven project which dont have a main class

I have a Selenium TestNG project created with maven. ``
There is no main class for this prject
Using TestNg.xml file and the same is configured in pom.xml file.
Ran 'maven test' from eclispe and the test runs successfully based on the classes defined in testng.xml. no issues here
Tried the same from command prompt using mvn test from the project folder and it ran succesfully. no issues here too.
My requirement : Now i want to package this project either to executable jar or are there are any option to make a executable file so that i can schedule the run using a batch file.
To do this I ran the 'mvn package' command and it generated the jar file in the target folder. Now when i try to run this as java -jar myproj-0.0.1-SNAPSHOT.jar i get the message as "no main manifest attribute, in myproj-0.0.1-SNAPSHOT.jar". This is expected behavior since there is no main class in my case.
So i created a main class with just one line to print "text" and added the mainClass below entry in pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<archive>
<manifest>
<mainClass>mainPackage.MainOne</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
Then i ran mvn package and it generated the new jar.
Then went to target folder of my project and ran the command as java -jar myProj.jar mainPackage.MainOne, it ran and just printed "text". MY TestNG tests did not run. It just ran main class :(..
What should i do?
Just to let you know that i have found a solution as provided in this How to programmatically call a Maven-task
as i mentioned I did use the main class. So i did the below
-Added the maven-invoker dependency in pom.xml
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-invoker</artifactId>
<version>2.1.1</version>
</dependency>
Updated my main class class as below using this link- http://maven.apache.org/shared/maven-invoker/usage.html
public class MainOne {
public static void main(String[] args) {
InvocationRequest request = new DefaultInvocationRequest();
request.setPomFile( new File( "pom.xml" ));
request.setGoals( Collections.singletonList( "install" ));
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome(new File(System.getenv("MAVEN_HOME")));
try {
invoker.execute( request );
} catch (MavenInvocationException e) {
e.printStackTrace();
}
}
}
Then from command prompt ran the command mvn clean package shade:shade
This created the jar in the target folder.
Copied the jar into Project folder and ran the command java -jar myproj-0.0.1-SNAPSHOT.jar, my tests starting running perfectly!!.
I did something similar with JUnit. I run my tests programmatically from main method. I don't know TestNG but you can look here how to do this - Running TestNG programmatically

JUnit + Maven: accessing ${project.build.directory} value

In my unit tests I want to create a tmp directory inside the ${project.build.directory}. How can I access the value of ${project.build.directory} inside my unit test?
One way, which I could think of, is to provide a filtered properties file in the test resources, which holdes that value. (I haven't tried yet, but I think that should work.)
Is there a direct way to access/ pass this property value?
I've used something like this with some success before. The unit test will still run even if not using Maven, the target directory will still get created two dirs up relative to the cwd of wherever the tests are run.
public File targetDir(){
String relPath = getClass().getProtectionDomain().getCodeSource().getLocation().getFile();
File targetDir = new File(relPath+"../../target");
if(!targetDir.exists()) {
targetDir.mkdir();
}
return targetDir;
}
I think using system properties is quite straightforward if you configure the surefire-plugin as explained here http://maven.apache.org/plugins/maven-surefire-plugin/examples/system-properties.html . Even the example there is answering your question directly:
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<systemPropertyVariables>
<propertyName>propertyValue</propertyName>
<buildDirectory>${project.build.directory}</buildDirectory>
[...]
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
[...]
</project>
Remember, that your unit tests don't have to be executed from Maven surefire plugin, so ${project.build.directory} property might not be available. To make your tests more portable I would rather recommend using File.createTempFile().

Categories

Resources