TestNG + Spring + Maven = Cannot load context - spring

I am using Maven with surefire plugin to run TestNG test by extending AbstractTestNGSpringContextTests and it appears the context is not loaded even if it is in classpath, and the test works correctly inside my ide, but not in maven.
#ContextConfiguration(locations =
Array("classpath*:/com/gottex/gottware/server/offlinepuwithdummydatafeed.xml"))
My xml is under src/test/com/gottex/gottware/server
My parent pom contains:
<build>
<defaultGoal>package</defaultGoal>
<testResources>
<testResource>
<directory>src/test/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<verbose>true</verbose>
<forkMode>never</forkMode>
</configuration>
</plugin> ...
and my children pom does not contain anything if not dependencies..

After a long debugging session, I was finally able to find the problem. It lies at ClassLoader level, and it exhibits itself when debugging
org.springframework.core.io.support.PathMatchingResourcePatternResolver
inside the method findAllClassPathResources
protected Resource[] findAllClassPathResources(String location) throws IOException {
String path = location;
if (path.startsWith("/")) {
path = path.substring(1);
}
Enumeration resourceUrls = getClassLoader().getResources(path);
Set<Resource> result = new LinkedHashSet<Resource>(16);
while (resourceUrls.hasMoreElements()) {
URL url = (URL) resourceUrls.nextElement();
result.add(convertClassLoaderURL(url));
}
return result.toArray(new Resource[result.size()]);
}
This is done when the context is loaded, and produce the following result:
When you run inside idea, the ClassLoader is java.net.URLClassLoader and this works correctly
When runnigng tests throuh Maven-Surefire plugin, a different classloader is used: ClassRealm[plugin>org.apache.maven.plugins:maven-surefire-plugin:2.9,
parent: sun.misc.Launcher$AppClassLoader#61ba34f2]
The second classLoader returns a enumeration resourceUrls with no "moreElements" and therefore the context is not loaded, but no failure is thrown by the framework.

Related

Cucumber option not running the tag scenario from mvn cli command

I want to run particular scenario from my feature file with the below command.
mvn test -Dcucumber.options="--tags #Smoke-Login"
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<configuration>
<encoding>UTF-8</encoding>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.version}</version>
<configuration>
<includes>
<include>**/TestRunner.java</include>
</includes>
<parallel>methods</parallel>
<threadCount>4</threadCount>
<useUnlimitedThreads>false</useUnlimitedThreads>
</configuration>
</plugin>
</plugins>
</build>
</project>
The below is my runner file for running the suite from pom.xml
#RunWith(Cucumber.class)
#CucumberOptions(
publish = true,
features = "classpath:features",glue = "stepDefinations",
plugin = {"junit:target/cucumber-results.xml","rerun:target/rerun.txt",
"pretty",
"json:target/cucumber-reports/CucumberTestReport.json"},
tags="#QA53",
monochrome = true
)
public class TestRunner {
#BeforeClass
public static void setup(){
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("mac")) {
PropertyConfigurator.configure(System.getProperty("user.dir")+"/src/test/resources/log4j.properties");
}
else {
PropertyConfigurator.configure(FileReader.getInstance().getConfigReader().getlog4jpath());
}
}
#AfterClass
public static void writeExtentReport() {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("mac")) {
}
else {
}
}
}
Here is my file structure in the below image.
If you are on a recent version of Cucumber (> 5.0) the syntax is cucumber.filter.tags=#Smoke-Login.
You should have this feature file specified in the runner file mentioned in the POM file. And the feature file should have the tag #Smoke-Login for the scenario u want to execute.
then u will be able to run with the below command
mvn test -Dcucumber.options="--tags -#Smoke-Login"

How can I get the version of the application (defined by tag version in pom.xml) in quarkus specially?

I moved from a plain Java EE application to quarkus.io.
In Java EE I had the a properties file with
version=${project.version} and reeading this file in an JAX RS endpoint. This worked very well.
#GET
public Response getVersion() throws IOException {
InputStream in = getClass().getClassLoader().getResourceAsStream("buildInfo.properties");
if (in == null) {
return Response.noContent().build();
}
Properties props = new Properties();
props.load(in);
JsonObjectBuilder propertiesBuilder = Json.createObjectBuilder();
props.forEach((key, value) -> propertiesBuilder.add(key.toString(), value.toString()));
return Response.ok(propertiesBuilder.build()).build();
}
Now that I am using quarkus and MicroProfile, I wonder if there is a better approach.
I tried it with the ConfigProperty setup from MicroProfile.
#ConfigProperty(name = "version")
public String version;
But I get the following error:
Property project.version not found.
Here is my build section of my pom.
<build>
<finalName>quarkus</finalName>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>1.0.0.CR2</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemProperties>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
Is there any solution / better approach?
Try
#ConfigProperty(name = "quarkus.application.version")
String version;
Also you can read the Implementation-Version from the manifest.
I'm not sure if my approach is the best case scenario but you can try this:
pom.xml :
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/application.properties</include>
</includes>
</resource>
</resources>
In application.properties use version property:
quarkus.version=${quarkus.platform.version}
Then use it as a config property:
#ConfigProperty(name = "quarkus.version")
String version;
Here is another way:
String projectVersion = ConfigProvider.getConfig().getValue("quarkus.application.version", String.class);
Or .getOptionalValue() etc

Cucumber Parallel Testing giving weird results

I'm trying to run my cucumber project (two runner classes) in parallel browsers and I am getting weird results. When I do a mvn verify, first it will run each runner class sequentially. The first will pass and the second will fail due to the following error -
org.openqa.selenium.NoSuchSessionException: Session ID is null. Using WebDriver after calling quit()?
Then right after, it will run both runner classes in parallel (like I want it to), and all will pass just fine. And maven will report the Build Success.
I am not initializing the webdriver in the #Before annotation. Instead I am using cucumber-picocontainer dependency injection right into my step definition classes. I have tried swapping driver.close() and driver.quit() in my #After annotation, but that didn't change the results. Please find some code snippets below and then my POM. Many thanks in advance.
public class GivenSteps {
WebDriver driver;
CustomWaits waits;
public GivenSteps(DependencyInjection dependencyInjection) {
this.driver = dependencyInjection.getDriver();
this.waits = dependencyInjection.getWaits();
}
Hooks -
public class Hooks {
WebDriver driver;
public Hooks(DependencyInjection dependencyInjection) {
this.driver = dependencyInjection.getDriver();
}
#Before("#setup")
public void setUp() {
driver.manage().deleteAllCookies();
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS);
}
#After("#destroy")
public void tearDown() throws Throwable {
//driver.close();
driver.quit();
}
Dependency Injection -
public class DependencyInjection {
private static String browserType = Settings.BROWSER.getValue();
private static WebDriver driver = null;
private static CustomWaits waits = null;
public WebDriver getDriver() {
if (driver == null) {
driver = utilities.DriverFactory.createDriver(browserType);
}
return driver;
}
POM.xml -
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
<includes>
<exclude>
**/*Runner.java
</exclude>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>com.github.temyers</groupId>
<artifactId>cucumber-jvm-parallel-plugin</artifactId>
<version>5.0.0</version>
<executions>
<execution>
<id>generateRunners</id>
<phase>generate-test-sources</phase>
<goals>
<goal>generateRunners</goal>
</goals>
<configuration>
<glue>
<package>test.java.stepDefinitions</package>
</glue>
<outputDirectory>target/generated-test-sources/cucumber</outputDirectory>
<featuresDirectory>src/test/resource/</featuresDirectory>
<cucumberOutputDir>target/Reports/</cucumberOutputDir>
<namingPattern>Runner{c}</namingPattern>
<!-- One of [SCENARIO, FEATURE]. SCENARIO generates one runner per
scenario. FEATURE generates a runner per feature. -->
<parallelScheme>FEATURE</parallelScheme>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<id>acceptance-test</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
</goals>
<configuration>
<forkCount>10</forkCount>
<reuseForks>true</reuseForks>
<includes>
<include>**/*Runner.class</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
I had to comment out the section in my POM.xml -> maven-surefire-plugin because now I am only using maven-failsafe-plugin
Originally I had both active in my POM, so both were running sequentially.

Maven mojo not picking up configuration from pom

I've written a Maven plugin and incorporated it as a goal in the package phase of another project with configuration given in that project's pom.xml. However, none of the fields set using the #parameter notation end up being populated so they just throw NullPointerExceptions when they get used.
My mojo:
/**
* #goal wrap
* #phase package
*/
public class MyMojo extends AbstractMojo {
/**
* #parameter expression="${project.build.directory}"
*/
private String outputDirectory;
/**
* #parameter
*/
private String dbDataName;
private File dbFile;
public MyMojo(){
dbFile = new File(outputDirectory, dbDataName) // throws nullpointerexception
}
public void execute() throws MojoExecutionException{
// Do stuff
}
}
Some of the mojo pom:
<groupId>com.mycompany.wrapper</groupId>
<artifactId>something-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>maven-plugin</packaging>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.2</version>
<configuration>
<skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
</configuration>
<executions>
<execution>
<id>mojo-descriptor</id>
<goals>
<goal>descriptor</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
The relevant bit of my project pom:
<plugin>
<groupId>com.mycompany.wrapper</groupId>
<artifactId>something-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>wrap</goal>
</goals>
<configuration>
<dbDataName>dcbTestData.sql</dbDataName>
</configuration>
</execution>
</executions>
</plugin>
Can anyone see what I'm doing wrong here? Most likely it's some silly mistake that I'm just not seeing.
I've solved the problem. I had done a few things wrong but after changing and tinkering, I managed to work it out.
Incidentally, this process was made rather harder by the fact that the Maven docs and user guides are a bit inconsistent about whether they prefer the annotations or the javadocs styles, and in some places they recommend deprecated methods, such as the expression="${stuff}" form.
Anyway to get it working:
I corrected the mistakes pointed out by khmarbaise in his first comment where I had slightly mangled the maven-plugin-plugin definition in my pom.
I updated to the Java annotations based way of denoting Mojos and parameters (it might have worked if I had done step 3 without doing this step, but it still seemed a good idea to update)
The main problem was that I was trying to access the parameter variables in the constructor to assign values to other variables but the mojo doesn't pick up the configuration details until the execute() method is run. So I just moved any variable assignments that used the parameters to the start of the execute() method and then they worked.
So here's what my mojo looks like now:
#Mojo(name = "wrap", defaultPhase = LifecyclePhase.PACKAGE)
public class MyMojo extends AbstractMojo {
#Parameter(property="project.build.directory")
private File outputDirectory;
#Parameter(property="dbDataName")
private String dbDataName;
private File dbFile;
public void execute()
throws MojoExecutionException {
dbFile = new File(outputDirectory, dbDataName);
// Do other stuff
}
}
You should change your code like the following:
/**
* #parameter default-value="${project.build.directory}"
*/
private String outputDirectory;

How to pass java code a parameter from maven for testing

I need to pass on following values …
exeEvironment (Test environment) ,
testGroup (Group in testNG)
from Command-Line -> POM -> TestNG -> Test cases.
Based on these two posts ....
pass a java parameter from maven
How to pass parameters to guicified TestNG test from Surefire Maven plugin?
I did the following configuration ..
In surefire plugin, I tried following two options, none seem to work.
=====
(1)
<execution>
<id>default-test</id>
<goals>
<goal>test</goal>
</goals>
<configuration>
<properties>
<exeEnvironment>${exeEnvironment}</exeEnvironment>
<testGroup>${testGroup}</testGroup>
</properties>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</execution>
(2)
<execution>
<id>default-test</id>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemPropertyVariables> <exeEnvironment>${exeEnvironment}</exeEnvironment>
<testGroup>${testGroup}</testGroup> </systemPropertyVariables>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</execution>
In testNG.xml , can I use the the variable testGroup like …
<test name="Web Build Acceptance">
<groups>
<run>
<include name="${testGroup} />
</run>
</groups>
<classes>
<class name="com.abc.pqr" />
</classes>
</test>
This doesn't seem to work as well, do I need to define a parameter.
In the test cases , I tried to get he variables in following two ways ….
(1)
testEnv = testContext.getSuite().getParameter("exeEnvironment");
testGroup = testContext.getSuite().getParameter("testGroup");
(2)
testEnv = System.getProperty("exeEnvironment");
testGroup = System.getProperty("testGroup");
This is the exact thing I was looking for my automation test and I got it working.
Command Line argument
mvn clean test -Denv.USER=UAT -Dgroups=Sniff
My Pom Xml
<?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>TestNg</groupId>
<artifactId>TestNg</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<systemPropertyVariables>
<environment>${env.USER}</environment>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
TestNG test
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
public class TestAuthentication {
#Test (groups = { "Sniff", "Regression" })
public void validAuthenticationTest(){
System.out.println(" Sniff + Regression" + System.getProperty("environment"));
}
#Test (groups = { "Regression" },parameters = {"environment"})
public void failedAuthenticationTest(String environment){
System.out.println("Regression-"+environment);
}
#Parameters("environment")
#Test (groups = { "Sniff"})
public void newUserAuthenticationTest(String environment){
System.out.println("Sniff-"+environment);
}
}
The above works well. Additionally, if you need to use testng.xml, you can specify the suiteXmlFile like ...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<systemPropertyVariables>
<environment>${env.USER}</environment>
</systemPropertyVariables>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
Also, I prefer using #Parameters instead of parameters in #Test() as the later is deprecated.
You need not define anything for groups in testng xml or the pom, the support comes inbuilt. You can simply specify the groups on the cmd line
http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html#groups
Hope it helps..
Edit 2:
Ok..so here's another option...Implement IMethodInterceptor
Define your custom property.
Use -Dcustomproperty=groupthatneedstoberun in your command line call.
In the intercept call, scan through all methods ..something to the effect..
System.getProperty("customproperty");
for(IMethodInstance ins : methods) {
if(ins.getMethod().getGroups()) contains group)
Add to returnedVal;
}
return returnedVal;
Add this to the listeners list in your xml.
Perfect.
The simplest way to pass the variable from POM.xml to ABC.java
POM.xml
<properties>
<hostName>myhostname.com</hostName>
</properties>
And in the ABC.java we can call it from the system properties like this
System.getProperty("hostName")
Passing parameter like browser and other can be done as below :
<properties>
<BrowserName></BrowserName>
<TestRunID></TestRunID>
</properties>
<!-- Below plug-in is used to execute tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/${testXml}</suiteXmlFile>
</suiteXmlFiles>
<systemPropertyVariables>
<browserName>${BrowserName}</browserName>
<testRunID>${TestRunID}</testRunID>
</systemPropertyVariables>
</configuration>
<executions>
<execution>
<id>surefire-it</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>false</skip>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</execution>
</executions>
</plugin>
and to handle this in java code use this :
public static final String Browser_Jenkin=System.getProperty("BrowserName");
public static final String TestRunID=System.getProperty("TestRunID");
public static String browser_Setter()
{
String value=null;
try {
if(!Browser_Jenkin.isEmpty())
{
value = Browser_Jenkin;
}
} catch (Exception e) {
value =propObj.getProperty("BROWSER");
}
return value;
}
public static String testRunID_Setter()
{
String value=null;
try {
if(!TestRunID.isEmpty())
{
value = TestRunID;
}
} catch (Exception e) {
value =propObj.getProperty("TEST_RUN_ID");
}
return value;
}
building on the accepted answer
if maven surefire and the <systemPropertyVariables> are declared in a maven profile, they are not available and will return null unless the profile is also invoked.
Command Line argument
mvn clean test -PmyTestProfile -Denv.USER=UAT -Dgroups=Sniff
pom.xml
<profiles>
<profile>
<id>myTestProfile</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire.version}</version>
<configuration>
<systemPropertyVariables>
<environment>${env.USER}</environment>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
You don't need to use environment variables or edit pom.xml to use them.
The goals and options for Invoke Maven 3 under Build section takes the parameter. Try this (assuming you parameterized the build):
Invoke Maven 3
Goals and options = test -Denv=$PARAM_ENV -Dgroup=$PARAM_GROUP

Resources