I have a framework where I have multiple classes and one of my class is a mojo class which gets some data from a different class and then pass that data to some other class for execution.
The first time when I use command mvn clean install I would get error - Could not find artifact com.io:MyDataProject:0.0.1-SNAPSHOT. Then I have to comment out the second plugin section inside build tag as shown below and again use command mvn clean install which would then install my plugin and once installed I would then uncomment the commented code again so that I can use my installed plugin which executes the mojo and then everything runs fine.
Issue is if I would share my project with other team members they have to do the same steps which I don't want. I need something like using mvn clean install would install my plugin and can execute my mojo at the same time.
#Mojo(name = "dependency-counter", defaultPhase = LifecyclePhase.COMPILE)
public class DependencyCounterMojo extends AbstractMojo {
public void execute() throws MojoExecutionException, MojoFailureException {
System.out.println("$$$$$$$$$$$$$$ ....Mojo execution begins.... $$$$$$$$$$$$$$");
GenerateFeature ob=new GenerateFeature();
ob.getData();
}
}
Pom.xml:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.4</version>
</plugin>
<plugin>
<groupId>com.io</groupId>
<artifactId>MyDataProject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<executions>
<execution>
<goals>
<goal>dependency-counter</goal>
</goals>
</execution>
</executions>
<configuration>
<scope>test</scope>
</configuration>
</plugin>
</plugins>
</build>
You need two separate projects or modules:
One for the plugin, containing the mojo and the POM for the plugin.
One for your framework, where the POM lists the plugin under <plugins>.
You cannot list the plugin in the same POM that produces the plugin.
You might also consider not putting the plugin into the POM at all, but run it on command line.
Related
I have a maven project project A that has a dependency on a different maven project project B. I publish Project B as two jars, one with the regular class files and one for its tests (I need to re-use some componenents). Maven has a plug-in for this.
The pom.xml for project A looks like this:
<properties>
<project-B.version>abcd123</project-B.version>
</properties>
<dependencies>
<dependency>
<groupId>group-id-project-B</groupId>
<artifactId>project-B</artifactId>
<version>${project-B.version}</version>
</dependency>
<dependency>
<groupId>group-id-project-B</groupId>
<artifactId>project-B</artifactId>
<classifier>tests</classifier>
<type>test-jar</type>
<version>${project-B.version}</version> <!-- Doesn't work! -->
<scope>test</scope>
</dependency>
</dependencies>
Somehow, both my IDE (IntelliJ) and mvn CLI are unable to compile this and both give an unresolved reference in my test classes (where I re-use test files from project B).
If, however, I replace ${project-B.version} with abcd123 in the test-jar dependency everything loads fine. I can't make any sense of this as to why mvn doesn't like me to use a variable in properties? This behaviour is consistent between my IDE and mvn cli.
For what it's worth, this is the output for project B when I use mvn dependency:list
group-id-project-B:project-B:test-jar:tests:abcd123:test
group-id-project-B:project-B:jar:tests:abcd123:compile
And the rest of my pom:
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
is there a bug in maven or am I missing something?
Edit:
I use mvn clean install and the truncated output is:
[INFO] --- kotlin-maven-plugin:1.3.72:test-compile (test-compile) # optimization-engine-service ---
[ERROR] MyClass.kt: (16, 19) Unresolved reference: functionName
[ERROR] MyClass.kt: (19, 28) Unresolved reference: SOME_FIELD
... etc.
Maven cannot resolve artifact that were installed/deployed with a version from parameter.
In order for your artifacts to be resolvable after build, you will have to use flatten-maven-plugin so you get an effective pom which will be resolvable by maven.
You can see an example on how to do this in maven-ci-friendly
I have a Spring Boot multi module Maven project, I can run integration tests with:
mvn clean verify
and it works well. I now want to run the same integration tests from a container and I don't want to embed all the source code in the container.
My question is : how can I run the Maven Failsafe Plugin without using the source code?
I tried to run the failsafe:integration-test goal and setting the dependenciesToScan parameter, from the command line:
mvn failsafe:integration-test -DdependenciesToScan=com.myorg:proj-tests.jar
but no tests are found.
P.S.1: I've seen this similar question Running spring tests from executable jar. But I don't need to run the tests without Maven. I prefer to run tests from the command line with Maven than adding code or modifying the structure of my project.
P.S.2: I'm using maven-failsafe-plugin 2.22.2 which is the version provided with Spring Boot 2.1.8.
From the docs:
Since version 2.22.0 you can scan for test classes from a project
dependency of your multi-module project.
It means the tests (proj-tests.jar) must be a dependency of the project. As you cannot have a dependency to the tests jar in the same project where you build them, the solution is to have another module or pom file. Example:
<groupId>failsafe.use.jar</groupId>
<artifactId>failsafe-use-jar</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
...
<dependency>
<groupId>com.myorg</groupId>
<artifactId>proj-tests</artifactId>
<version>0.0.1-SNAPSHOT</version>
<classifier>tests</classifier>
</dependency>
...
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
The proj-tests is a project dependency and can be created with:
<groupId>com.myorg</groupId>
<artifactId>proj-tests</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
See Guide to using attached tests
To run the integration tests from the container you obviously need all the dependencies installed in the local
(container) maven repository or deployed in remote. Then you can run with:
mvn failsafe:integration-test -DdependenciesToScan=com.myorg:proj-tests
Note that the format of the dependenciesToScan property is groupId:artifactId (you run with the name of jar instead of artifactid)
As another note, for integration tests failsafe searches by default for class files ending in IT (integration test).
I've got a plugin that I need to use in my build. This plugin, however, has a build-time dependency on another plugin and that dependency does not work post-Java-8.
Specifically, the plugin that I want to use has this in its pom.xml file
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>${javaVersion}</version>
<scope>system</scope>
<systemPath>${tools.jar}</systemPath>
</dependency>
</dependencies>
<executions>
<execution>
<phase>test-compile</phase>
......
</execution>
</executions>
</plugin>
It's set to the test-compile phase, so it's only ever run when the plugin itself is being built, and not when it's being used.
The problem is that it's got the systemPath as part of the dependency, and this is set to something that is not resolvable using Java 9+. That in turn causes the build for the project using the plugin to fail with:
[ERROR] 'dependencies.dependency.systemPath' for com.sun:tools:jar must specify an absolute path but is ${tools.jar} #
So either I need to completely ignore the maven-antrun-plugin as part of my using this plugin, or I need to at least make the dependencies for it work.
Any thoughts?
Cheers
I'm trying to run java selenium tests using a testng xml file via command line. I moved all my jars (testNg,selenium,jcommander...) in a single folder and add in the classpath by using something like set classpath="singlefolder\*;" from the command line.
Reference:
http://learn-automation.com/execute-selenium-test-from-command-line/
I managed to do this using a simple test:
Test Class:
public class SampleTest {
#Test
public void testCase1() {
// Create webDriver reference
FirefoxDriver driver;
// Launch FirefoxDriver
driver = new FirefoxDriver();
// Close the driver
driver.quit();
}
#Test
public void testCase2() {
Assert.assertEquals("1", "1");
}
}
TestNG XML (test.xml) File:
<suite name="Suite 1" >
<test name="Test 1" >
<classes>
<class name="NBS.testcases.SampleTest" />
</classes>
</test>
</suite>
Problem:
This is not working when I try to run my actual tests.
Some notes:
1. My tests are having some dependencies -- common methods being called from a compiled jar within the project.
2. My test extends other classes from within the same project
3. The 'extended' class [UITestTriggerProject] is not on the same folder with the test classes.
4. The 'extended' classes may vary from each test, and each extended class may or may not be extending further classes that are from the same or other folders.
5. The said compiled jar on item 1 is already added in the classpath.
6. The same test class is running fine when the test.xml is triggered from within eclipse via the plugin.
My test class:
package NBS.testcases;
import java.lang.reflect.Method;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import Automation.framework.dataModel.CaseInfo;
import NBS.config.*;
#Listeners({ WebTestListener.class })
public class LoginWithBayanUser extends UITestTriggerProject{
String xlsDataFilePath = "/excel_data/moduleA/LoginWithBayanUser.xlsx";
#DataProvider(name = "dataInfo1")
public Object[][] dataInfo1(Method method) {
Object[][] myObj = setTestData(xlsDataFilePath, method.getName());
return myObj;
}
#Test(dataProvider="dataInfo1")
public void tcLoginWithUser1(CaseInfo tc) throws Exception {
logTestCaseID(tc);
loginHomePage().tsLoginWithBayanUser(tc);
loginHomePage().tsSelectLogicType(tc);
loginHomePage().tsLogoutWithBayanUser();
}
}
Result when test.xml from cmd:
[TestNG] [ERROR]
Cannot instantiate class NBS.testcases.LoginWithBayanUser
Questions:
1. Why is this happening? Is this a testNG limitation? - the test runs just fine when fired from the eclipse plugin.
2. How do I solve the problem?
3. Apart from putting all the jars in one folder and adding them in the classpath, is there another way to run testng from command line more efficiently? The reason I'm trying to avoid this is my dependent jars are stored on my local maven repo that is already included in the project. Collating them all in one location seems to be redundant and just adds clutter.
Thanks in advance!
============================================================
UPDATE 1:
I tried to accomplish the same by using the maven build + pom file as advised by #Cathal and now I'm getting a different error.
My project was already a maven project to begin with, all dependencies were already added. (surefire, testNg, selenium...). I just had to modify the surefire config with the correct xml name
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testngRunner/test.xml</suiteXmlFile>
</suiteXmlFiles>
Execution steps:
1. Open command prompt
2. Enter the following:
set projectLocation=C:\Users\johndoe\Documents\My Docs\03_OE\Java\workspace\KeywordDrivenTool\JavaTestNBS
cd %projectLocation%
set classpath=%projectLocation%\target\test-classes\;%projectLocation%\lib\*;
mvn surefire:test -DtestSuite=test.xml
This works with SampleTest.java but not with LoginWithBayanUser.java
Error:
[TestNGClassFinder] Warning: Can't link and determine methods of class NBS.testcases.LoginWithBayanUser
This error also happens when I try to run the pom.xml as Maven test from within eclipse. Hoping you can help!
============================================================
UPDATE 2:
Managed to resolve the maven issue by adding the custom jar being called by LoginWithBayanUser.java under maven pom.xml dependencies.
I can now run my tests in cmd prompt using the maven command listed above. However, would still want to know why the problem happens with testNG + cmd line. Any information would be appreciated. Thank you.
Have you considered using a build tool like maven for your project? It designed to do exactly what your asking. All of your project configuration is contained within one file. Your tests are more portable and it allows for easy execution of your test scripts anywhere.
Here is a basic example pom.xml configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>groupName</groupId>
<artifactId>artificatId</artifactId>
<version>0.0.2</version>
<name>Selenium Tests</name>
<properties>
<!-- compiler settings -->
<maven.compiler.sources>1.8</maven.compiler.sources>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- build info -->
<build.timestamp>${maven.build.timestamp}</build.timestamp>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<testng.congig>${testSuite}</testng.congig>
<aspectj.version>1.8.9</aspectj.version>
<allure.version>1.4.14</allure.version>
</properties>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.allure</groupId>
<artifactId>allure-testng-adaptor</artifactId>
<version>${allure.version}</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${maven.compiler.sources}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<argLine>
-javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
</argLine>
<suiteXmlFiles>
<suiteXmlFile>target\test-classes\${testng.congig}</suiteXmlFile>
</suiteXmlFiles>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/test/resources</directory>
<includes>
<include>*.xml</include>
</includes>
</resource>
</resources>
</build>
<reporting>
<excludeDefaults>true</excludeDefaults>
<plugins>
<plugin>
<groupId>ru.yandex.qatools.allure</groupId>
<artifactId>allure-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</reporting>
</project>
Executing your script from the command line is as easy as:
mvn -fn clean install -DtestSuite=YOUR_TEST_SUITE.xml
Maven is highly configurable and allows you to setup your projects as you like.
Heres a more detailed explanation:
http://toolsqa.com/java/maven/configure-selenium-continuous-integration-maven/
Problem : I want to access com.sun.tools.javadoc.Main from code in a Mojo plugin.
I have two parts to this question.
Part 1:
When creating a mojo plugin, is it best to use annotations or parameters inside the #Mojo
For example you can set 'requiresDependencyResolution' in both.
/*
* #goal install
* #phase process-classes
* #configurator include-project-dependencies
* #requiresDependencyResolution compile+runtime
*/
#Mojo(name = "document", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
public class CreatorMavenPlugin extends AbstractMojo
Part 2: (Main question)
I want to execute the following code in my plugin, I want to hook into the Javadoc generation.
com.sun.tools.javadoc.Main.execute(new String[]
{
"-private",
"-doclet",
"com.test.tools.APIDocGenDoclet",
javaFilePathAndName
});
return APIDocGenDoclet.getCurrentClassDocs();
The problem is that eclipse recognises com.sun.tools.javadoc.Main from the JDK it has.
Maven when it runs can't find the class and gives the error....
Number of foreign imports: 1
import: Entry[import from realm ClassRealm[maven.api, parent: null]]
-----------------------------------------------------
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:125)
... 20 more
Caused by: java.lang.NoClassDefFoundError: com/sun/tools/javadoc/Main
I've tried adding tools directly to start with as a dependency...
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.6.0</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
But this doesn't work. (Same error)
I've tried adding it as a dependency of the profile my plugin runs under...
<profile>
<id>auto-doc</id>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.6.0</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.test</groupId>
<artifactId>updater</artifactId>
<version>1.0.0-SNAPSHOT</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>document</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
But not change, same error.
I feel this is something to do with the classpath setup defined for the Mojo Plugin, but I've tried many different combinations, but I'm stumped.
Can anyone help please?
Note: I'm using Maven 3.0.4 & JDK 1.6.0_43 32 bit on Windows.
Part 1: if you don't need backward compatibility with ancient Maven versions, go with the annotations. It's the new and better way of specifying Mojo configuration, and your IDE will give you autocomplete and hovers.
Part 2:
Taking a look at what the existing Maven Javadoc plugin does:
It seems it uses the Toolchain API to locate the appropriate Javadoc tool to run. The Maven Compiler Plugin also does this to get javac.
Summarizing from the toolchain documentation:
add
#Component
private ToolchainManager toolchainManager;
#Component
private MavenSession session;
to your Mojo. Then in your code
Toolchain tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
String javadocExecutable = tc.findTool( "javadoc" );
and then you can execute it. Read the toolchain documentation in the link for more detailed information.
If you were using Java 8 or later, you could use ToolProvider.getSystemDocumentationTool().
I was putting the Profile section in the project that was being built, not in the project that contains the Mojo Plugin.
This is what I've got in Mojo Plugin Project
<profiles>
<profile>
<id>default-tools.jar</id>
<activation>
<property>
<name>java.vendor</name>
<value>Sun Microsystems Inc.</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.6.0</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
</profile>
</profiles>
The Mojo plugin is defined as this...
/**
* #goal install
* #phase process-classes
* #configurator include-project-dependencies
* #requiresDependencyResolution compile+runtime
*/
#Mojo(name = "document", requiresDependencyResolution= ResolutionScope.COMPILE_PLUS_RUNTIME)
public class DocumationUpdatorMavenPlugin extends AbstractMojo
My project that uses the plugin, has this in its POM...
<profile>
<id>auto-doc</id>
<build>
<plugins>
<plugin>
<groupId>com.test</groupId>
<artifactId>updater</artifactId>
<version>1.0.0-SNAPSHOT</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>document</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Then my command "mvn install -Pauto-doc" kicks off my AutoDoc plugin.