Not able to run Quarkus unit and integration test in gitlab-ci - quarkus

I'm trying to setup my quarkus project with gitlab-ci and I'm constantly running into the next problem.
Right now I'm trying to figure out how quarkus is running unit test vs integration test.
Both unit test and integration test work if run from the command line like this:
export QUARKUS_PROFILE=test
./mvnw verify
But when running from gitlab-ci it runs in containers and I just don't seem to be able to find out the right environment to setup.
The build stage below (only unit test - #QuarkusTest) runs fine.
When adding integration test (./mvnw verify) it will fail with the database connection failed.
The verify stage below however fails on the unit tests.
If I disable the unit tests (with #Disabled) the integration tests (#QuarkusIntegrationTest) runs fine with below environment variables.
It seems like unit tests needs the default postgress url (QUARKUS_DATASOURCE_REACTIVE_URL - not sure how to figure out what the actual default value is), but in integration test on gitlab this will fail with: Connect Connection refused). This can be solved with using the QUARKUS_DATASOURCE_REACTIVE_URL below.
Here is my application.properties
quarkus.container-image.group=yyyy/slideshow
quarkus.container-image.insecure=true
quarkus.container-image.registry=xxxx:5555
quarkus.container-image.build=true
quarkus.rest-client.piwigo-api.url=https://<hostname>
quarkus.datasource.devservices.enabled=true
quarkus.datasource.db-kind=postgresql
quarkus.hibernate-orm.database.generation=drop-and-create
%prod.quarkus.http.port=9090
%test.quarkus.http.port=9080
%test.quarkus.http.test-port=9081
%test.quarkus.hibernate-orm.sql-load-script=import.sql
Here is my gitlab-ci (quarkus-dev is my own image: eclipse-temurin:17 with docker-ce):
image: xxxx:5555/yyyy/util/quarkus-dev:0.1.0
variables:
IMAGE: "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME"
stages:
- build
- verify
- docker
unit-test:
stage: build
script:
- ./mvnw test
integration-test:
stage: verify
variables:
QUARKUS_PROFILE: test
QUARKUS_DATASOURCE_REACTIVE_URL: "vertx-reactive:postgresql://<ip docker host>:5432/quarkus?loggerLevel=OFF"
TEST_URL: "http://<ip docker host>:9081"
script:
- ./mvnw verify
docker-build:
stage: docker
when: manual
variables:
QUARKUS_CONTAINER_IMAGE_PUSH: "true"
script:
- ./mvnw install -DskipTests
A minimal example:
I based this example based on https://github.com/quarkusio/quarkus-quickstarts/tree/main/hibernate-reactive-panache-quickstart.
Dockerfile for the image used to run the pipeline in gitlab (/quarkus-dev:0.1.0)
FROM eclipse-temurin:17 as builder
RUN apt-get update && \
apt-get install -y apt-transport-https ca-certificates curl software-properties-common && \
apt-get clean
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - && \
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" && \
apt-get clean
RUN apt-get install -y docker-ce && \
apt-get clean
Updated dockerfile src/main/docker/Dockerfile.jvm (changed to java 17):
FROM registry.access.redhat.com/ubi8/openjdk-17:1.14
ENV LANGUAGE='en_US:en'
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080
USER 185
ENV AB_JOLOKIA_OFF=""
ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
Updated pom file (similar to my failing project)
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.acme</groupId>
<artifactId>hibernate-reactive-panache-quickstart</artifactId>
<version>0.1.0-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.10.1</compiler-plugin.version>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>2.15.2.Final</quarkus.platform.version>
<surefire-plugin.version>3.0.0-M7</surefire-plugin.version>
<assertj.version>3.24.2</assertj.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-reactive-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-pg-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-docker</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<skipITs>false</skipITs>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
</project>
Updated Application properties:
quarkus.container-image.group=<group-name>
quarkus.container-image.insecure=true
quarkus.container-image.registry=<registery url>
quarkus.container-image.build=true
quarkus.datasource.devservices.enabled=true
quarkus.datasource.db-kind=postgresql
quarkus.hibernate-orm.database.generation=drop-and-create
%test.quarkus.http.port=9080
%test.quarkus.http.test-port=9081
%test.quarkus.hibernate-orm.sql-load-script=import.sql
Updated unit test:
package org.acme.hibernate.orm.panache;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.response.Response;
import static io.restassured.RestAssured.given;
import static org.assertj.core.api.Assertions.assertThat;
#QuarkusTest
public class FruitsEndpointTest {
#Test
#Disabled
public void testListAllFruits() {
//List all, should have all 3 fruits the database has initially:
Response response = given()
.when()
.get("/fruits")
.then()
.statusCode(200)
.contentType("application/json")
.extract().response();
assertThat(response.jsonPath().getList("name")).containsExactlyInAnyOrder("Cherry", "Apple", "Banana");
}
}
Updated integration test:
package org.acme.hibernate.orm.panache;
import io.quarkus.test.junit.QuarkusIntegrationTest;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.response.Response;
import static io.restassured.RestAssured.given;
import static org.assertj.core.api.Assertions.assertThat;
#QuarkusIntegrationTest
public class FruitsEndpointIT {
#Test
#Disabled
public void testListAllFruits() {
//List all, should have all 3 fruits the database has initially:
Response response = given()
.when()
.get("/fruits")
.then()
.statusCode(200)
.contentType("application/json")
.extract().response();
assertThat(response.jsonPath().getList("name")).containsExactlyInAnyOrder("Cherry", "Apple", "Banana");
}
}
Minimal gitlab-ci.yml:
image: <xxx>/quarkus-dev:0.1.0
stages:
- verify
unit-test:
stage: verify
script:
- ./mvnw test
integration-test:
stage: verify
variables:
QUARKUS_PROFILE: test
QUARKUS_DATASOURCE_REACTIVE_URL: "vertx-reactive:postgresql://<docker host ip>:5432/quarkus?loggerLevel=OFF"
TEST_URL: "http://<docker host ip>:9081"
script:
- ./mvnw verify
Running on the cmdline the following works:
export QUARKUS_PROFILE=test
./mvnw verify
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
The above example also works on the gitlab runner.
However, as you se the unit test is disabled.
After enabling it still works locally (mvnw verify), but it will fail on the gitlab runner.
The unit-test job will succeed, but the integration-test job will fail on the unit tests.
2023-01-28 12:34:45,902 ERROR [org.hib.rea.errors] (vert.x-eventloop-thread-3) HR000057: Failed to execute statement [select fruit0_.id as id1_0_, fruit0_.name as name2_0_ from Fruit fruit0_ order by fruit0_.name]: could not execute query: java.util.concurrent.CompletionException: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /<ip>:5432
.
.
.
[ERROR] Failures:
[ERROR] FruitsEndpointTest.testListAllFruits:22 1 expectation failed.
Expected status code <200> but was <500>.

Related

Java 8 to Java 17 migration + pitest failing - Mutation testing requires a green suite

Recently , the project has been migrated from Java8 to Java17 . The mutation test coverage is also checked for the project and before migration there was no known issues during the command run of mvn clean install org.pitest:pitest-maven:mutationCoverage
After migration , the issue is reported as Execution default-cli of goal org.pitest:pitest-maven:1.7.6:mutationCoverage failed: 6 tests did no
t pass without mutation when calculating line coverage. Mutation testing requires a green suite.
The pom.xml file has
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.6.2</version>
<dependencies>
<dependency>
<groupId>org.pitest</groupId>
<artifactId>pitest-junit5-plugin</artifactId>
<version>0.12</version>
</dependency>
</dependencies>
</plugin>
Note: There are few test cases contain Whitebox.invokeMethod to invoke the private method. There are no issues during the run of the test cases - mvn clean install.
The actual problem occurred during the run of mutation test coverage with the command - mvn clean install org.pitest:pitest-maven:mutationCoverage
I tried to include the option --add-opens java.base/jdk.internal.misc=ALL-UNNAMED in pom.xml file but of no use.
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
--add-opens java.base/jdk.internal.misc=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
I tried to change the version of pitest-maven as 1.7.3 from 1.6.2 and pitest-junit5-plugin as 0.15 from 0.12. This is also not useful.
Any idea or suggestion to overcome the pitest-maven in Java17 with WhiteBox.invokeMethod in test cases.
The correct version of pitest-junit5-plugin was helpful to get rid of the error.
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.11.0</version>
<groupId>org.pitest</groupId>
<artifactId>pitest-junit5-plugin</artifactId>
<version>1.1.2</version>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.2</version>
Along with the junit pitest-junit5-plugin addition , adding --add-opens is also required ,
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.11.0</version>
<dependencies>
<dependency>
<groupId>org.pitest</groupId>
<artifactId>pitest-junit5-plugin</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
<configuration>
<argLine>
--add-opens java.base/java.lang=ALL-UNNAMED
</argLine>
</configuration>
</plugin>

Junit test works only when renamed test class name

I am using junit4 to run test. My test class is as below in test->java->com.example->ProductIT.java
When I run mvn clean install on my project, below test is not recognized and not run.
However, when I rename the test class to ProductTest, it works.
I do not understand the difference. Why does it work when I rename ?
#ContextConfiguration(locations = {"classpath:META-INF/spring/test-config.xml"})
#RunWith(SpringJunit4ClassRunner.class)
public class ProductIT{
#Autowried
private ProductServiceImpl serviceImpl;
#Test
public void test() throws Exception{
assertNotNull(serviceImpl)
}
}
pom.xml
<dependencyManagement>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core></artifactId>
<version>4.2.4-RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-infrastructure></artifactId>
<version>4.2.4-RELEASE</version>
</dependency>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch></artifactId>
<dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter></artifactId>
<dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test></artifactId>
<scope>test</scope>
<dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
The *IT postfix (for integration test) is the default test identifier for the Maven Failsafe plugin. Spring Boot projects don't contain this plugin by default and you have to explicitly add it to your project.
The *Test postfix is the default test identifier for the Maven Surefire Plugin which is used as part of the test phase of the default lifecycle: mvn test.
This answer sheds more light on the differences between these plugins.
In case you want to split your tests (unit & integration) and run them separately (first unit, then integration), add the Maven Failsafe Plugin to your project:
<project>
<!-- other dependencies -->
<build>
<!-- further plugins -->
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M5</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
... and it should recognize your existing ProductIT when you run mvn verify (or mvn install).
For more information on such testing defaults and standards, consider this guide on testing Java applications with Maven.

Quarkus: Try to cache maven dependencies using multistage docker build

I have got a simple Quarkus application and I try to build it using the following multistage Dockerfile.
FROM maven:3-jdk-8-slim AS build
WORKDIR /build
# Download Dependencies
COPY pom.xml .
RUN mvn dependency:go-offline
# Build App
COPY src/ /build/src/
RUN mvn -Dmaven.test.skip=true package -Dcheckstyle.skip
# Stage 2 : create the docker final image
FROM adoptopenjdk:8-jre-openj9 AS runtime
COPY --from=build /build/target/*-runner.jar /app/app.jar
COPY --from=build /build/target/lib/* /app/lib/
WORKDIR /app
RUN chgrp -R 0 /app &&\
chmod g=u /app
USER 1001
EXPOSE 8080
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app/app.jar"]
and the pom.xml
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>booking-mgr</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus-plugin.version>1.1.1.Final</quarkus-plugin.version>
<quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>1.1.1.Final</quarkus.platform.version>
<surefire-plugin.version>2.22.1</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-reactive-messaging-kafka</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
</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>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemProperties>
<native.image.path>
${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
</project>
The build works fine, it downloads the maven dependencies, then it creates the .jar and runs the .jar in the final container. But if I change something in the source code and leave the pom.xml untouched, the dependencies are downloaded again. It seems that mvn dependency:go-offline does not download all dependencies.
Is there a way to speed up docker builds that way? For example, I do the same with Spring Boot and everything works great there.
Thank you for your help.
Your pom.xml and src folder are in the build context (the dot in your command).
If you change files in src then you change your build context so you invalidate the COPY cache.
See Docker build is not using cache
Simply, you can split the Dockerfile into two, such as builder-base.dockerfile and final.dockerfile. Then, create a directory builder-base and move pom.xml into builder-base.
directory structure:
.
+-- builder-base
| +-- pom.xml
|-- src
|-- builder-base.dockerfile
|-- final.dockerfile
In the final.dockerfile is :
FROM java-builder AS build
# Build App
COPY src/ /build/src/
RUN mvn -Dmaven.test.skip=true package -Dcheckstyle.skip
# Stage 2 : create the docker final image
FROM adoptopenjdk:8-jre-openj9 AS runtime
COPY --from=build /build/target/*-runner.jar /app/app.jar
COPY --from=build /build/target/lib/* /app/lib/
WORKDIR /app
RUN chgrp -R 0 /app &&\
chmod g=u /app
USER 1001
EXPOSE 8080
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app/app.jar"]
First, put this code into builder-base.dockerfile:
FROM maven:3-jdk-8-slim
WORKDIR /build
# Download Dependencies
COPY pom.xml .
RUN mvn dependency:go-offline
So, at first, you should build a image named 'java-builder'
docker build -t java-builder -f builder.dockerfile ./builder-base
Now, you can compile the source code use the command below:
docker build -t app -f final.dockerfile .
The base image in the final.dockerfile is java-builder, if you don't re-build the image, you can always create the docker final image using the cache.
I found mvn package will do the work.
Now I use:
COPY pom.xml .
RUN mvn --batch-mode \
--quiet \
--errors \
dependency:go-offline \
package
COPY src ./src
RUN mvn --batch-mode \
--quiet \
--errors \
--define maven.test.skip=true \
--define java.awt.headless=ture \
clean package
Looks weird, but no errors.

How to run using terminal on IntelliJ Idea using Maven?

I'm new to IntelliJ IDEA and I would like to run my test through the terminal lines.
I already run my test using the Run button and my test are all passed. Now, my requirement in project is to run using the command lines/terminal. I really don't have any idea how to do it.
I'm using Appium as my tool for mobile automation.
This is all where my tests are located, C:\Users\ereyne\IdeaProjects\ioappium\src\test\java\io
Tests location
I already look on google but all are in high level, can anyone provide me step by step process on how to do it?
Test java classes
This 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">
<modelVersion>4.0.0</modelVersion>
<groupId>io.appium</groupId>
<artifactId>io.appium</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/io.appium/java-client -->
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>7.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
</project>
This is my code in IntelliJ:
//package io;//package appium;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.MobileElement;
import io.appium.java_client.remote.MobileCapabilityType;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.By;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.net.URL;
import java.net.MalformedURLException;
public class appium {
public AndroidDriver<MobileElement> driver;
public WebDriverWait wait;
DesiredCapabilities dc = new DesiredCapabilities();
int CustomerNumber = 10088214;
int AccessCode = 44445555;
String SignIn = "/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View/android.view.View[1]/android.view.View/android.view.View/android.view.View/android.view.View[2]/android.widget.Button[3]";
String MakeaPayment = "/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View/android.view.View[1]/android.view.View/android.view.View/android.view.View[2]/android.view.View[2]/android.widget.Button[4]";
#BeforeMethod
public void setUp() throws MalformedURLException {
dc.setCapability("deviceName", "Pixel XL API 28");
dc.setCapability("udid", "ce041714789604830d"); //DeviceId from "adb devices" command //Tab S3-674ce8f9 S8-ce041714789604830d
dc.setCapability("platformName", "Android");
dc.setCapability("platformVersion", "9.0");
dc.setCapability("skipUnlock","true");
dc.setCapability("appPackage", "com.loans.smartmoney");
dc.setCapability("appActivity","com.loans.smartmoney.MainActivity");
dc.setCapability("noReset","true");
dc.setCapability("automationName", "UiAutomator2");
driver = new AndroidDriver<MobileElement>(new URL("http://127.0.0.1:4723/wd/hub"),dc);
wait = new WebDriverWait(driver, 30);
}
#Test
public void testLoginTest() {
//Login
wait.until(ExpectedConditions.visibilityOfElementLocated
(By.xpath(SignIn)));
driver.findElement(By.xpath(SignIn)).click();
driver.findElement(By.className("android.view.View")).click();
driver.findElement(By.className("android.widget.EditText")).sendKeys(String.valueOf(CustomerNumber));
driver.findElements(By.className("android.widget.EditText")).get(1).click();
driver.findElements(By.className("android.widget.EditText")).get(1).sendKeys(String.valueOf(AccessCode));
driver.findElements(By.className("android.widget.Button")).get(1).click();
wait.until(ExpectedConditions.visibilityOfElementLocated
(By.xpath(MakeaPayment)));
}
#AfterMethod
public void tearDown() {
driver.quit();
}
}
I run this is terminal: C:\Users\ereyne\IdeaProjects\ioappium>mvn appium.java
Errors: [ERROR] Unknown lifecycle phase "appium.java". You must specify a valid lifecycle phase or a goal in the format : or :[:]:. Available lifecycle phases are: validate, initialize, generat e-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integr ation-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles:
I also try to run this in my terminal: C:\Users\ereyne\IdeaProjects\ioappium\src\test\java\io>javac appium.java
And the result is everything does not exist, just a sample error below.
appium.java:2: error: package io.appium.java_client does not exist import io.appium.java_client.MobileBy;
IntelliJ-IDEA actually has a built-in terminal that you can run maven commands in at a project level. Simply click the "terminal" button on the very bottom bar. If you don't see it, try "Alt+F12". If your terminal is disabled, press Shift twice, type "Terminal" and turn it on.
From there, you can run maven commands. The valid lifecycle phases are:
clean
validate
compile
test
package
verify
install
site
deploy
So within that terminal, you'll already be on the right directory, and can run valid maven commands. For example
mvn clean
mvn verify
mvn test -e
You will want the Maven-Compiler-Plugin, and either the Maven-Surefire-Plugin or Maven-Failsafe-plugin. For my own personal project, this is the pom.xml that I use containing those plugins.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-surefire-plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
</plugin>
</plugins>
</build>
The 'source' and 'target' denote what Java version my project uses. These plugins allow me to both run my project as a maven project, and have specific things happen at different instances of the lifecycle.
In my case, during the "verify" phase, maven triggers a plugin of mine to log results, and create a report.
If you're getting the error
'mvn' is not recognized as an internal or external command, operable program or batch file.
This means that Maven was not added to your PATH correctly. It can be a little confusing, but this video helped me a lot.
If you want to check your maven installation, open a new terminal, and run the following
mvn -v
You should get the response (with your system details)
Apache Maven 3.6.0 (97c98ec64a1fdfee7767ce5ffb20918da4f719f3; 2018-10-24T14:41:47-04:00)
Maven home: C:\Program Files\apache-maven-3.6.0\bin\..
Java version: 1.8.0_201, vendor: Oracle Corporation, runtime: C:\Program Files\Java\jdk1.8.0_201\jre
Default locale: en_US, platform encoding: Cp1252
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
Edit: To answer your question below in more detail, I use a TestRunner class designed for the Cucumber framework, and I do not have a main method in my program at all. My Test class is as follows:
package Runner;
import cucumber.api.CucumberOptions;
import cucumber.api.testng.AbstractTestNGCucumberTests;
#CucumberOptions(
plugin = {"pretty", "html:target/cucumber-pretty", "json:target/Cucumber.json"},
features = {"src/test/resources/Features"},
glue = {"StepDefinitions"},
tags = {"#smoke"},
monochrome = true
)
public class AppiumTest extends AbstractTestNGCucumberTests {
}
As you can see, my Test class doesn't have any code inside of it, and simply points to specific tests that I've built, and executes those. In the case of using TestNG as a test suite, it will look a lot different, and is a little bit easier to understand what is being tested, but check these resources to make sure you understand what to do.
https://testng.org/doc/documentation-main.html#testng-xml
https://howtodoinjava.com/testng/how-to-execute-testng-tests-with-maven-build/
Based on your reply, odds are, you've already got a TestNG suite built, and just need to tie it into maven.
The structure of a pom.xml is fairly straightforward, so you can use this to help you put the plugins you need into yours. I've included a copy of my pom.xml for a testing suite using Cucumber and Appium, just so you can see the format. I highly encourage you to keep the comments including the repository information in the event you need to update them in a hurry.
<?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>groupID</groupId>
<artifactId>MobileAutomation</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
<plugin>
<groupId>net.masterthought</groupId>
<artifactId>maven-cucumber-reporting</artifactId>
<version>4.6.0</version>
<executions>
<execution>
<id>execution</id>
<phase>verify</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<projectName>Test</projectName>
<outputDirectory>${project.build.directory}/cucumber-report-html</outputDirectory>
<inputDirectory>${project.build.directory}</inputDirectory>
<jsonFiles>
<param>Cucumber.json</param>
</jsonFiles>
</configuration>
</execution>
</executions>
</plugin>
<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-surefire-plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<failIfNoSpecifiedTests>false</failIfNoSpecifiedTests>
<failIfNoTests>false</failIfNoTests>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>4.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-picocontainer -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>4.3.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-junit -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>4.3.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-testng -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>4.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.5.0-M1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.appium/java-client -->
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>7.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
</dependencies>
</project>
As you can see, in my pom.xml I have a plugin that generates a test report during the "Verify" phase of Maven. When I want to run a test, I will run
mvn clean verify
This clears out any of my old test results, and runs the maven "Verify" cycle. Verify will run the tests I specify, and then depending on the results of my tests, the maven build will either succeed or fail.
If you see a maven build failure, that doesn't mean your code failed to execute, it means that maven had a reason to fail a build. Read about the specific maven plugins and lifecycle phases to understand what causes build failures, and what behaviors to expect out of maven.

NoClassDefFoundError when attempting to run unit tests when building Jenkins plugin

I have a custom Jenkins plugin that I've built. I have some test cases that leverage some code out of the jenkins-test-harness project (namely the Junit JenkinsRule.)
Anyway, the unit tests run and pass when I run them in IntelliJ. No exceptions, no errors.
When I try to run them from the Maven commandline, however, all of the tests that rely on the JenkinsRule fail:
[ERROR] testGetLastDate(com.mycompany.myplugin.portlet.utils.UtilsHudsonTest) Time elapsed: 0 s <<< ERROR!
java.lang.NoClassDefFoundError: Could not initialize class org.jvnet.hudson.test.TestPluginManager
at org.jvnet.hudson.test.JenkinsRule.<init>(JenkinsRule.java:325)
at com.mycompany.myplugin.portlet.utils.UtilsHudsonTest.<init>(UtilsHudsonTest.java:19)
That TestPluginManager is in the jenkins-test-harness jar. The JenkinsRule that attempts to call it is right next to it in the same package in the same jar, so clearly the jar itself is successfully on the classpath.
I can't quite figure out why I can't run this job from the commandline using mvn test.
My POM is very simple -- I declare a Parent on the Jenkins plugin-3.2 pom:
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>3.2</version>
<relativePath/>
</parent>
And I have a dependency on the test harness:
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>dashboard-view</artifactId>
<version>${dashboard-view.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-test-harness</artifactId>
<scope>test</scope>
<version>2.34</version>
</dependency>
</dependencies>
(That's the entire dependencies section, no omissions.)
And in my build section, I only declare the compiler, surefire, and hpi plugins:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
<plugin>
<groupId>org.jenkins-ci.tools</groupId>
<artifactId>maven-hpi-plugin</artifactId>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>hpi</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
</plugins>
</build>
(The surefire config is inherited from the plugin-3.2 parent.)
Here's the bit of the UtilHudsonTest that causes the error -- line 19 is the #Rule annotation:
public class UtilsHudsonTest {
#Rule // This is line 19
public JenkinsRule j = new JenkinsRule();
#Test
public void testGetLastDate() throws Exception {
FreeStyleProject prj = j.createFreeStyleProject("prj1");
prj.scheduleBuild2(0).get();
FreeStyleProject prj2 = j.createFreeStyleProject("prj2");
prj2.scheduleBuild2(0).get();
List<Job> jobs = new ArrayList<>();
jobs.add(prj);
jobs.add(prj2);
LocalDate lastDate = Utils.getLastDate(jobs);
assertNotNull(lastDate);
}
// other tests
}
I'm kind of stumped why this would work in IntelliJ and not in Maven. A mvn dependency:tree shows that the correct and expected dependencies. Any ideas in how to get this plugin to successfully run its test from commandline?

Resources