Spring Boot With Cucumber Integration - spring

I have been working on a spring boot application I would like to test with cucumber (for business driven development). I can successfully run the cucumber tests with my code, or I can boot the spring context, but I cannot seem to figure out a way to do both at once. I have looked around, and found a few tutorials (such as https://medium.com/#bcarunmail/set-up-and-run-cucumber-tests-in-spring-boot-application-d0c149d26220) that all seem to have this working. I followed the same premise as them, that is, (1) having one class that loads the spring context, (2) having another class be the entry point for discovering the cucumber tests, and finally, (3) a class containing the step definitions that extends the class with the context referenced in number one.
Here are my classes
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.testcontainers.containers.MySQLContainer;
import com.connor.Application;
/**
* This class should take care of initializing the test container (for the database) and populating it using the
* sql files that run against the actual db, in the actual order they execute. This guarantees these will run
* before we even use a staging region. Once the database is created, it boots the spring context the spring context
* and configures the environment with the db-related info from the test container.
*
* When ran alone, this test successfully performs the above steps and can be used for integration tests.
* However, when this class is extended by other classes (the glue code classes), it does not boot the spring context
* and hence do not work for integration tests.
* #author connor
*
*/
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = Application.class)
#ContextConfiguration(initializers = SpringContextConfigForCukeUsage.Initializer.class)
//#Ignore //even with this, still need a test method to compile
public /* abstract */ class SpringContextConfigForCukeUsage { //with or without abstract, this doesn't seem to work . . .
/**
* Use with String.format to build the base url string when testing locally.
*/
private static final String LOCAL_BASE_URL_FORMAT_STR = "%s:%d";
/**
* Create the mysql test container as a class rule.
*/
#ClassRule
public static MySQLContainer<?> mysqlDb = new MySQLContainer<>("mysql:latest") //TODO may not want the latest version . . .
.withInitScript("schema.sql");
/**
* The base url for the tests. By passing in here, we allow for testing actual environments, as well as integration tests with the same code.
* If no value is passed, defaults to localhost, and will be combined with port to build base url
*/
#Value("${BASE_URL:locahost}")
private String baseUrl;
/**
* For getting access to the port the spring boot context is running on in subclasses
*/
#LocalServerPort
protected int serverPort;
//Decide whether to use rest template or test res template here
/**
* Used in subclasses to get access to the base url for testing.
* #return
*/
protected String getBaseUrl() {
String baseUrlToReturn;
//if it is local, append the port
if(baseUrl != null && baseUrl.contains("localhost")){
baseUrlToReturn = String.format(LOCAL_BASE_URL_FORMAT_STR, baseUrl, serverPort);
}
//otherwise, return the environment variable, which will always be available on standard http(s) port
else {
baseUrlToReturn = baseUrl;
}
return baseUrlToReturn;
}
/**
* This initalizer class takes care of setting the properties from the test container into environment variables.
* This allows integration tests to be as close to real testing as possible.
* #author connor
*
*/
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
//add the url, username, and password to the test context before it starts
TestPropertyValues.of(String.format("spring.datasource.url=%s", mysqlDb.getJdbcUrl()),
String.format("spring.datasource.username=%s", mysqlDb.getUsername()),
String.format("spring.datasource.password=%s", mysqlDb.getPassword()))
.applyTo(applicationContext.getEnvironment());
}
}
/**
* This method is only here to test when running alone for debugging . . .
*/
#Test
public void test() {
//just here for compilation when testing this class by itself-- will not execute if no test here
}
}
Here is the second class, the one with the entry point for the cucumber tests
import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
/**
* This is the entry point for running the cucumber tests.
* #author connor
*
*/
#RunWith(Cucumber.class)
#CucumberOptions(features = "src/it/resources/AddingAssessment.feature")
public class RunCukesIT {
//intentionally blank -- annotations do all the work
}
Finally, here is my third class containing my step definitions:
import cucumber.api.java8.En;
/**
* This class contains the glue code for the "given when then" step definitions.
* This extends the class that bots the spring context, but it does not boot the
* context
* #author connor
*
*/
//even with these annotations, it does not load spring boot context
//#RunWith(SpringRunner.class)
//#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = Application.class)
//#ContextConfiguration(initializers = SpringContextConfigForCukeUsage.Initializer.class)
public class CukeGWT extends SpringContextConfigForCukeUsage implements En {
public CukeGWT() {
Given("we are attempting to add a test for a book", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n" + serverPort); //always 0 (because context doesn't load)
//
System.out.println("Env property is " + System.getenv("local.server.port")); //this also indicates server doesn't start
});
Given("the book has isbn {int}", (Integer int1) -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Given("the author of the book has first name conn", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Given("the author of the book has last name b", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Given("the book has {int} questions", (Integer int1) -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Given("one of the questions has incorrect answers a hen, a cat", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Given("the question has correct answer a dog", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
When("the api is called", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Then("the api will return a valid response", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Then("the isbn will match", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Then("the author's first name will match", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Then("the author's last name will match", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Then("the question added above will exist", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Then("the book will be unverified", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Given("the author of the book has first name test", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Given("the author of the book has last name testing", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Given("one of the questions has incorrect answers true", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Given("the question has correct answer false", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Given("an assessment with valid data is generated", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Then("the api will return an error response", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Then("the http status code will be {int}", (Integer int1) -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
Then("the error message will contain A test already exists for this book", () -> {
// Write code here that turns the phrase above into concrete actions
//throw new cucumber.api.PendingException();
});
}
}
Here is my pom for reference of the dependencies/versions
<?xml version="1.0" encoding="UTF-8"?>
https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.3.RELEASE
com.connor
reading-comprehension-api
0.0.1-SNAPSHOT
reading-comprehension-api
This is the containerized webservice for reading
comprehension
<properties>
<!-- miscellaneous properties -->
<docker.image.prefix>connordocker</docker.image.prefix>
<java.version>1.8</java.version>
<!-- get as much info as we can locally for development -->
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
<!-- versions, please keep in alphabetical order -->
<cucumber.version>4.2.5</cucumber.version>
<testcontainer.version>1.12.4</testcontainer.version>
</properties>
<dependencies>
<!-- bring this in once database is integrated and defined in properties
file -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<!-- lets us connect to mysql db -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- lets us use test containers; must use same version as mysql test container
below -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>${testcontainer.version}</version>
<scope>test</scope>
</dependency>
<!-- mysql specific test container; must use same version as testcontainers -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mysql</artifactId>
<version>${testcontainer.version}</version>
<scope>test</scope>
</dependency>
<!-- the below three dependencies are required for cucumber tests -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java8</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- create different profiles for each ci/cd stage -->
<profiles>
<!-- this is ran for every commit -->
<profile>
<id>commit-profile</id>
<activation>
<!-- if we make this active by default, it runs, even when we explicitly
mention another profile -->
<!-- active by default -->
<!-- <activeByDefault>true</activeByDefault> -->
</activation>
<build>
<!-- TODO add compile plugin, surefire plugin here -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<!-- inherit surefire plugin for running unit tests. Overwrite and add
additional configuration to ignore our integration tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- ignore the integration tests (named *IT) which come from src/it/java,
but are placed on classpath by the build helper plugin (IT must be on test
classpath to run, but we don't want them running here) -->
<excludes>
<exclude>**/*IT.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<!-- this is ran on the merge to master -->
<profile>
<id>merge-to-base-branch-profile</id>
<!-- active when stage is merge -Dstage=merge -->
<activation>
<property>
<name>stage</name>
<value>merge</value>
</property>
</activation>
<!-- TODO add enforcer plugin, failsafe plugin, codehaus plugin -->
</profile>
<!-- this is ran and triggered by a tag -->
<profile>
<id>deploy-profile</id>
<!-- active when stage is deploy -Dstage=deploy, should be triggered by
tag from pipeline -->
<activation>
<property>
<name>stage</name>
<value>deploy</value>
</property>
</activation>
<!-- not sure if we want to (or can) trigger deployment to cloud from
maven, or if we can -->
</profile>
<!-- this profile is triggered for running integration tests -->
<profile>
<id>integration-test-profile</id>
<!-- make to skip unit tests so we don't get confused -->
<properties>
<skipTests>true</skipTests>
</properties>
<build>
<plugins>
<!-- this plugin adds folders to the classpath. As of right now, it
takes care of adding the integration tests (and feature files) to test classpath. -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<!-- this execution adds the src/it/java to test classpath -->
<execution>
<id>add-integration-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/it/java</source>
</sources>
</configuration>
</execution>
<!-- this execution adds the src/it/resources to test classpath -->
<execution>
<id>add-integration-test-resource</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>src/it/resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!-- this runs the integration tests -->
<!-- NOTE: I have been considering using this for e2e tests once deployment
is done to staging region. This would allow us to reuse code, with the only
change being the base url system property passed in. However, we still have
to deal with populating the region database, and the fact we want our integration
tests to be much more extensive than our e2e tests, which should be very
brief -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<id>integration-tests</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<!-- this is needed so we can skip unit tests here, but not integration tests (as both default to skip tests property, which we set to true to ignore unit tests) -->
<skipTests>false</skipTests> <!-- NOTE: In future here, could configure with ${skip.failsafe.tests} or any other variable but skip tests -->
<!-- only run integration tests, which should end in IT -->
<includes>
<include>**/*IT.java</include>
</includes>
<excludes>
<exclude>**/*Test.java</exclude>
</excludes>
<!-- set the environment variable from what is passed in as a system
variable. This allows use with spring boot property injection NOTE: there
is no need to set the jdbc related info here, this comes from test container -->
<environmentVariables>
<!-- set the base url; if not set defaults to localhost for int
testing -->
<BASE_URL>${BASE_URL}</BASE_URL>
</environmentVariables>
</configuration>
</execution>
</executions>
</plugin>
<!-- this plugin builds a pretty(ier) html report from the results of
cucumber tests. This should only be active in this profile, after int tests
have ran -->
<plugin>
<groupId>net.masterthought</groupId>
<artifactId>maven-cucumber-reporting</artifactId>
<version>2.8.0</version>
<!-- we have one execution tag per functionality exposed by the api -->
<executions>
<!-- for the add integration tests -->
<execution>
<id>addCucumberReport</id>
<phase>verify</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<projectName>CucumberWebGui</projectName>
<outputDirectory>${project.build.directory}/cucumber-report-html/add</outputDirectory>
<cucumberOutput>${project.build.directory}/cucumber-report/addCucumber.json</cucumberOutput>
</configuration>
</execution>
<!-- for get integration tests -->
<execution>
<id>getCucumberReport</id>
<phase>verify</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<projectName>CucumberWebGui</projectName>
<outputDirectory>${project.build.directory}/cucumber-report-html/get</outputDirectory>
<cucumberOutput>${project.build.directory}/cucumber-report/getCucumber.json</cucumberOutput>
</configuration>
</execution>
<!-- for the verify/udpate reports -->
<execution>
<id>updateCucumberReport</id>
<phase>verify</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<projectName>CucumberWebGui</projectName>
<outputDirectory>${project.build.directory}/cucumber-report-html/update</outputDirectory>
<cucumberOutput>${project.build.directory}/cucumber-report/verifyCucumber.json</cucumberOutput>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<!-- NOTE: this is the build tag. Every plugin specified here will always
run, regardless of if a profile is selected, or if there are multiple profiles
selected. -->
<build>
<plugins>
<!-- This is the default spring boot plugin that wraps as jar and allows
running with embedded instance -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<!-- display active profile in compile phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<executions>
<execution>
<id>show-profiles</id>
<phase>compile</phase>
<goals>
<goal>active-profiles</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
The source code for this can be found at: https://gitlab.com/connorbutch/reading-comprehension-api

Related

How to get the configuration in my Custom Annotation Processing whitch was defined in my Maven plugin

My goal is read a parameter's value from costom Maven Plugin
during the processing of process, I need this value to determine whether to process annotations.
Here is what i done:
customize a maven plugin to configure the parameter of funProcess
#Mojo(defaultPhase = LifecyclePhase.COMPILE, threadSafe = true,
requiresDependencyResolution = ResolutionScope.COMPILE)
public class PamirsFunctionMojo extends AbstractMojo {
#Parameter
private Boolean funProcess;
#Override
public void execute() throws MojoExecutionException, MojoFailureException {
//todo
this.getPluginContext().put("funProcess", funProcess);
}
}
this is my maven-plugin's definition.
<groupId>pro.xxx.pamirs.plugin</groupId>
<artifactId>pamirs-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>2.0.0-SNAPSHOT</version>
Build a project to process annotation #Fun which is defined in method. So,I need to define A Annotation Processor through extends AbstractProcessor,handle the method corresponding to this #Fun annotation in the process interface.
Using the value in my Annotation Processor.
I need the value of funProcess which is configured within the pom of business project which relying on this Annotation Processor project, then using the value to determine whether to process annotations In the Annotation Processor project.
The test project will rely on annotation processing projects and my maven-plugin.
This is the POM definition .
<dependencies>
<dependency>
<groupId>pro.xxx.pamirs.annotation</groupId>
<artifactId>annotation-processor</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>pro.xxx.pamirs.plugin</groupId>
<artifactId>pamirs-maven-plugin</artifactId>
<version>2.0.0-SNAPSHOT</version>
<executions>
<execution>
<configuration>
<funProcess>false</funProcess>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</dependency>
I want to know how to get the value in my Annotation Processor.

Maven Surefire does not give correct test counts when executing Spock tests in parallel

My project contains a series of Groovy integration test scripts for a few APIs. Previously, these tests executed concurrently and took up to 3 hours to execute. I was able to reduce this time to just 5 minutes by using Spock's parallel execution feature.
The new problem is that the Maven Surefire reports no longer give the correct test counts for each test suite. The total test count is correct (more or less), but Surefire is mixing up which tests go in which report.
Here is my pom:
<?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">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.dsg.payments</groupId>
<artifactId>e2e</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>This will be used to execute normal credit card End2End test cases</description>
<properties>
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<build-helper-maven-plugin.version>3.1.0</build-helper-maven-plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven-surefire-plugin.version>3.0.0-M3</maven-surefire-plugin.version>
<gmavenplus-plugin.version>1.11.0</gmavenplus-plugin.version>
<swagger-annotations-version>1.6.0</swagger-annotations-version>
<groovy.version>3.0.7</groovy.version>
<spock.version>2.0-M4-groovy-3.0</spock.version>
</properties>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>${groovy.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>${spock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger-annotations-version}</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>0.15</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}-${project.version}</finalName>
<testSourceDirectory>${project.basedir}/src/test/groovy</testSourceDirectory>
<resources>
<resource>
<directory>src/test/groovy</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/groovy</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</testResource>
</testResources>
<plugins>
<!-- Groovy compiler -->
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>${gmavenplus-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>addTestSources</goal>
<goal>compileTests</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Java compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- Unit Tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<includes>
<include>**/*.java</include>
</includes>
<skipTests>false</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</project>
Here is an example of a test class
package com.dsg.payments.e2e.creditcard
import com.dsg.payments.paygate.ApiClient
import com.dsg.payments.paygate.api.AuthorizationApi
import com.dsg.payments.paygate.model.PaygateAuthorizationRequest
import com.dsg.payments.paygate.model.PaygateAuthorizationResponse
import com.dsg.payments.paygate.model.PaygateEncryptedCardTenderResult
import org.junit.Test
import org.springframework.http.HttpStatus
import org.springframework.web.client.HttpClientErrorException
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Title
import spock.lang.Unroll
import util.Constants
import util.CreditCardType
import util.EntityFactory
#Title("CreditCard-Authorization")
class Authorization extends Specification {
// Constants
#Shared
private static final applicationName = Constants.APPLICATION_NAME
#Shared
private static final referer = Constants.REFERER
#Shared
private static final basePath = Constants.BASE_PATH
#Shared
private AuthorizationApi authorizationApi
def setupSpec() {
// Setup ApiClient to make requests to stage AN01
ApiClient authApiClient = new ApiClient()
authApiClient.setBasePath(basePath)
authorizationApi = new AuthorizationApi(authApiClient)
}
#Test
#Unroll
def "Auth request with valid #cardType card returns authorized response"(CreditCardType cardType) {
when:
PaygateAuthorizationResponse authorizationResponse = authorizationApi.authorize(applicationName, EntityFactory.getPaygateAuthorizationRequest(cardType), referer)
PaygateEncryptedCardTenderResult tenderResult = authorizationResponse.getTenderResults().getEncryptedCardTenderResults().get(0)
then:
// No exception thrown by authorization api client means successful 201 response
authorizationResponse != null
where:
cardType << [
CreditCardType.VISA_Credit_1,
CreditCardType.VISA_Debit,
CreditCardType.VISA_Commercial_Debit,
CreditCardType.VISA_Commercial_Credit,
CreditCardType.VISA_Purchasing_Credit,
CreditCardType.VISA_3DS_Not_Enrolled,
CreditCardType.DISCOVER,
CreditCardType.AMERICANEXPRESS_1,
CreditCardType.MASTERCARD_Debit,
CreditCardType.MASTERCARD_Credit,
CreditCardType.MASTERCARD_Premium_Credit,
CreditCardType.DINERS,
CreditCardType.JAPANCREDITBUREAU
]
}
#Test
#Unroll
def "Auth request with valid cvv for #cardType returns cvv response M"(CreditCardType cardType) {
when:
PaygateAuthorizationResponse authorizationResponse = authorizationApi.authorize(applicationName, EntityFactory.getPaygateAuthorizationRequest(cardType), referer)
PaygateEncryptedCardTenderResult tenderResult = authorizationResponse.getTenderResults().getEncryptedCardTenderResults().get(0)
then:
// No exception thrown by authorization api client means successful 201 response
authorizationResponse != null
tenderResult.getCvvResponse() == "M" // Raw CVV result code for "match"
where:
cardType << [
CreditCardType.VISA_Credit_2,
CreditCardType.VISA_Debit,
CreditCardType.VISA_Commercial_Debit,
CreditCardType.VISA_Commercial_Credit,
CreditCardType.VISA_Purchasing_Credit,
CreditCardType.VISA_3DS_Not_Enrolled,
CreditCardType.DISCOVER,
CreditCardType.AMERICANEXPRESS_2,
CreditCardType.MASTERCARD_Debit,
CreditCardType.MASTERCARD_Credit,
CreditCardType.MASTERCARD_Premium_Credit,
CreditCardType.DINERS,
CreditCardType.JAPANCREDITBUREAU
]
}
// ...
}
There are 3 more test classes (Capture, Refund, and Cancel) with a similar structure that use the #Unroll annotation to re-run the same test with different credit card numbers.
Interestingly, when using Spock parallel execution, Surefire adds an extra test to the report for each test method - one for each credit card and an additional test for the method itself. This is not a huge problem in itself, but it is less than ideal. The real problem is that the Surefire report mixes the classes together (for example, Capture tests end up in the Refund, Cancel, or Authorization reports). This makes it hard to tell from the report which tests failed.
I'll also include my SpockConfig.groovy, which configures the parallel execution:
runner {
filterStackTrace false
optimizeRunOrder true
parallel {
enabled true
dynamic(4.0)
}
}
It has taken much trial and error to get the pom in a state where the tests are all executing correctly in parallel fashion. This is the only combination of dependencies, plugins, and versions that works so far. The only thing that is wrong are the Surefire reports. Any ideas what I am missing?
First: I notice the surefire version in the POM shown is 3.0.0-M3. The mvnrepository.com maven-surefire-plugin list shows the latest is 3.0.0-M5 and a lot of the changes in the newer versions appear to be report related.
Second: check the Maven output log to see if the maven-surefire-report-plugin is being used. If it's there, ensure it is using the same version of Surefire as was used to run the tests. You can do that by adding this to the POM:
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
You may not be using Failsafe for integration tests yet, but it's a good idea to keep the Surefire family of plugins using the same version. So when I need to adjust Surefire version, I set them all in the hope of saving someone future troubleshooting pain.

How to execute cucumber features parallely?

I have below feature files (Separate feature files) in src/test/resources/feature/ and I would like to run them in parallel. Like: One feature file has to execute in chrome and another one has to execute in another chrome instance as mentioned #Tags name.
#Regression
Scenario: Searching for HelpMate on Company Hompe page
Given I navigate to application URL
Then I verified title "Company - Production - Sign In" on Login Page
after
launched the URL
When I type username as "defined in config" in username filed on Login
page
And I type password as "defined in config" in password filed on Login
page
And I click Login button on Login page
And I wait for 15 seconds
Then I verified title "Company - Production - My Applications" on
Login Page
#Regression
Scenario Outline: Searching for different options on Company Home
page
Given I navigate to application URL
Then I verified title "Company - Production - Sign In" on Login Page
after launched the URL
When I type username as "defined in config" in username filed on Login
page
And I type password as "defined in config" in password filed on Login
page
And I click Login button on Login page
And I wait for 15 seconds
I'm using cucumber-java 1.2.5 version, and AbstractTestNGCucumberTests as runner. I'm able to run a single feature file but when i try to run 2 feature files using cucumber-jvm-parallel-plugin v#4.0.0 and maven surefire plugin v#2.40, it is not initialing the test class
(Error:cucumber.runtime.CucumberException: cucumber.runtime.CucumberException: Failed to instantiate class com.cvs.stepdefinition.LoginPage)
This error is gone after I used updated cucumber dependencies
cucumber-jvm-parallel-plugin-- Not using anymore as it is not required with latest version of cucumber libraries
<plugin>
<groupId>com.github.temyers</groupId>
<artifactId>cucumber-jvm-parallel-plugin</artifactId>
<version>4.0.0</version>
<executions>
<execution>
<id>generateRunners</id>
<phase>validate</phase>
<goals>
<goal>generateRunners</goal>
</goals>
<configuration>
<glue>
<pakage>com.cvs.stepdefinition</pakage>
</glue>
<featuresDirectory>src/test/resources/features
</featuresDirectory>
<cucumberOutputDir>${project.build.directory}/
cucumberparallel</cucumberOutputDir>
<format>json,html</format>
<testFailureIgnore>true</testFailureIgnore>
<tags>
<tag>#Regression</tag>
</tags>
</configuration>
</execution>
</executions>
</plugin>
maven-surefire-plugin--UPDATED
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
TestNG.xml--UPDATED
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Testng Cucumber Suite" parallel="tests"configfailurepolicy="continue" thread-count="2">
<test name="SmokeSuite">
<parameter name="browserName" value="chrome"/>
<classes>
<class name="com.cvs.runner.TestSuiteRunner"></class>
</classes>
</test>
</suite>
I have tried overriding the method from AbstractTestNGCucumberTests and set the parallel attribute in #DataProvider annotation to true but still getting the same error.
#DataProvider(parallel=true)
public Object[][] features() {
return testNGCucumberRunner.provideFeatures();
}
POM.XML
<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>testNewBDD</groupId>
<artifactId>TestAutomation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>TestAutomation</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
<mainClass>ReportGenerator</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-filtering</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java8 -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java8</artifactId>
<version>4.2.6</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>4.2.6</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>4.2.6</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.14.0</version>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>3.6.0</version>
</dependency>
</dependencies>
</project>
Runner
#CucumberOptions(
strict = true,
monochrome = true,
features = {"src/test/resources/features"},
tags={"#Regression"},
glue = {"stepDef", "utils"},
plugin = {"pretty", "html:target/cucumber-html-report","json:target/cucumber-html-report/TestHomePage.json"},
//junit ={ "--step-notifications"},
dryRun = false
)
public class UITest {
private TestNGCucumberRunner testNGCucumberRunner;
#BeforeClass(alwaysRun = true)
public void setUpClass() throws Exception {
testNGCucumberRunner = new TestNGCucumberRunner(this.getClass());
}
#Test(groups = "cucumber", description = "Runs Cucumber Feature", dataProvider = "scenarios")
public void scenario(PickleEventWrapper pickleEvent, CucumberFeatureWrapper cucumberFeature) throws Throwable {
testNGCucumberRunner.runScenario(pickleEvent.getPickleEvent());
}
#DataProvider(parallel=true)
public Object[][] scenarios() {
return testNGCucumberRunner.provideScenarios();
}
#AfterClass(alwaysRun = true)
public void tearDownClass() throws Exception {
testNGCucumberRunner.finish();
}
}
There is only one feature file having 2 scenarios and i want these 2 scenarios to run on two different browser parallely. Please help me to resolve this.
Key Point : We would request you to use Cucumber-JVM v4.x.x specially to implement parallel execution without using cucumber-jvm-parallel-plugin as you are using pretty old dependency(v1.2.5) of Cucumber.
Note : In below implementation, we would be reading browser parameter from TestNG.xml file
First - Update POM.xml with correct set of io.cucumber dependencies as per any cucumber v >= 4.0.0 lets pick v4.2.6
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>4.2.6</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>4.2.6</version>
</dependency>
Second - Customize TestNGRunner class as per your framework need
package com.jacksparrow.automation.suite.runner;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
import com.jacksparrow.automation.steps_definitions.functional.BaseSteps;
import cucumber.api.CucumberOptions;
import cucumber.api.testng.AbstractTestNGCucumberTests;
#CucumberOptions(features = "classpath:features/functional/",
glue = {"com.jacksparrow.automation.steps_definitions.functional" },
plugin = { "pretty","json:target/cucumber-json/cucumber.json",
"junit:target/cucumber-reports/Cucumber.xml", "html:target/cucumber-reports"},
tags = { "#BAMS_Submitted_State_Guest_User" },
junit ={ "--step-notifications"},
strict = false,
dryRun = false,
monochrome = true)
public class RunCukeTest extends Hooks {
}
Third - Implement Hooks.java
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
import cucumber.api.testng.AbstractTestNGCucumberTests;
public class Hooks extends AbstractTestNGCucumberTests {
#Parameters({ "browser" })
#BeforeTest
public void setUpScenario(String browser){
//BaseSteps.getInstance().getBrowserInstantiation(browser); your browser setup method
}
}
Fourth - Update TestNG.xml under /src/test/resources/ as per your TestNGRunner Class and framework need.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Testng Cucumber Suite" parallel="tests" thread-count="2">
<test name="SmokeTest">
<parameter name="browser" value="chrome" />
<classes>
<class name="com.cvs.runner.TestSuiteRunner" />
</classes>
</test>
</suite>
Fifth - You shall be all set to run automation suite using TestNG in any of the following ways
- Run TestNG.xml directly from IDE
- From CMD - mvn test -Dsurefire.suiteXmlFiles=src/test/resources/testng.xml
- From POM.xml - Using Surefire Plugin
<profiles>
<profile>
<id>selenium-tests</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Did you try to add number of treads in your .xml file, I do have it in mine.
So your .xml file will be:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Testng Cucumber Suite" parallel="tests" thread-count="2">
<test name="SmokeSuite">
<classes>
<class name="com.cvs.runner.TestSuiteRunner"></class>
</classes>
</test>
</suite>
(Also try to change parallel = "tests" to parallel methods. And if you r using priorities in your tests parallel running is not gonna work)
Cucumber 4 provides native support to run scenarios(not by features) in parallel.
you have to update your pom.xml dependencies to latest cucumber version.
cucumber-core 4.2.0, cucumber-java 4.2.0, cucumber-junit 4.2.0
In the runner file, you have add "--thread 2 " like a plugin. this will run the scenario in 2 threads.

AspectJ + Junit + Maven + Java8

I followed this SO question and tried to implement it for java8. My project is not a spring project.
Aspect
#Aspect
public class MethodLogger {
#Pointcut("execution(#org.junit.Test * *())")
public void testMethodEntryPoint() {}
#Before("testMethodEntryPoint()")
public void executeBeforeEnteringTestMethod() {
System.out.println("EXECUTE ACTION BEFORE ENTERING TEST METHOD");
}
#After("testMethodEntryPoint()")
public void executeAfterEnteringTestMethod() {
System.out.println("EXECUTE ACTION AFTER ENTERING TEST METHOD");
}
}
JUnit Test
#RunWith(JUnit4.class)
public class POSTaggerTest {
#Test
public void test() {
...
}
}
POM.xml
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<aspectLibraries>
<aspectLibrary>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</aspectLibrary>
</aspectLibraries>
<!-- java version -->
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<!-- End : java version -->
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
</execution>
</executions>
</plugin>
:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<type>maven-plugin</type>
</dependency>
I don't see any error. Am I missing something? Or any wrong artifact? What I want when I run junit tests, all the aspects whould work fine.
The situation you want to recreate is like this:
There is one Maven module with aspects. It is compiled with AspectJ Maven Plugin.
There is another module with the actual application and test code. It is also compiled with AspectJ Maven, this time referring to the first module as an aspect library.
What you are doing though is:
You have a single module. This is not a problem in and of itself because it is easily possible to keep aspects and Java code within the same module if you want the aspects applied on this module only.
But now you declare JUnit as an aspect library. Why? It does not contain any aspects. You should remove that declaration.

Mock aspect in junit failed to apply

I'm building up a simple project to learn aspectj.
It's from aspect in action 2nd and the idea is very simple ---- the MessageCommunicator will be responsible for delivering the message and it's the main business logic. Meanwhile, Authenticator will be responsible for authentication and will be weaved as declared SecurityAspect.
Though it's very straightforward to see in the log that the aspect is working. Still I want to ensure it works in junit case.
In my project, I'm using maven 3.0.4 with aspectj 1.7.3 and aspect-maven-plugin 1.5.
Now the problem is below warning is there when compile the test case. As the consequence, the aspects in test package doesn't work. However, if you write a Main class in source package and run, the aspect in source package will work.
The warning message while build:
[INFO] --- aspectj-maven-plugin:1.5:test-compile (test-compile_with_aspectj) # aspectj ---
[WARNING] advice defined in org.javen.study.aspectj.c02.aspects.MockAuthenticationAspect has not been applied [Xlint:adviceDidNotMatch]
[WARNING] advice defined in org.javen.study.aspectj.c02.aspects.SecurityAspect has not been applied [Xlint:adviceDidNotMatch]
[WARNING] advice defined in org.javen.study.aspectj.c02.aspects.TrackingAspect has not been applied [Xlint:adviceDidNotMatch]
I will also attach all the related source code below:
MessageCommunicator who is responsible for the main business:
package org.javen.study.aspectj.c02;
public class MessageCommunicator {
public void deliver(String message) {
System.out.println(message);
}
public void deliver(String person, String message) {
System.out.println(person + ", " + message);
}
}
Simple version of authenticator which will do the authentication:
public class Authenticator {
public void authenticate() {
System.out.println("authenticated");
}
}
SecurityAspect which will advice on MessageCommunicator:
package org.javen.study.aspectj.c02.aspects;
import org.javen.study.aspectj.c02.Authenticator;
public aspect SecurityAspect {
private Authenticator authenticator = new Authenticator();
declare warning
: call(void Authenticator.authenticate())
&& !within(SecurityAspect)
: "Authentication should be performed only by SecurityAspect";
pointcut secureAccess() : execution(* org.javen.study.aspectj.c02.MessageCommunicator.deliver(..));
before() : secureAccess() {
System.out.println("Checking and authenticating user");
authenticator.authenticate();
}
}
MockAuthenticationAspect in test package to advice the authenticator to inject some verification logic(no need to look into advice detail, the advice implementation is problematic):
package org.javen.study.aspectj.c02.aspects;
import org.javen.study.aspectj.c02.Authenticator;
public aspect MockAuthenticationAspect {
declare parents: Authenticator implements Callable;
private boolean Callable.isCalled;
public void Callable.call() {
isCalled = true;
}
public boolean Callable.isCalled() {
return isCalled;
}
Object around(Callable accessTracked) : execution(* Authenticator.authenticate(..))
&& !execution(* Callable.*(..))
&& this(accessTracked) {
accessTracked.call();
return null;
}
private static interface Callable {
}
}
The pom of whole project:
<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>org.javen.study</groupId>
<artifactId>aspectj</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<aspectj.version>1.7.3</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.5</version>
<configuration>
<complianceLevel>1.6</complianceLevel>
<includes>
<include>**/*.java</include>
<include>**/*.aj</include>
</includes>
</configuration>
<executions>
<execution>
<id>compile_with_aspectj</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile_with_aspectj</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
When build with command "mvn clean install", the warning texts will be printed and the test package advice will not work. However, if check with AJDT in eclipse, all the pointcut and advice is working.
Could someone help me? Thanks a lot.
The problem is solved by added below configuration in test-compile execution.
<execution>
<id>test-compile_with_aspectj</id>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<weaveDirectories>
<weaveDirectory>target/classes</weaveDirectory>
</weaveDirectories>
</configuration>
</execution>
Don't know it's a good pratice or not, but at least now it works.

Resources