I have a gradle project that is built by Jenkins within the following steps:
Now step 4 is not ready yet and I am wondering about how to implement this in the most convenient way..?
I want to use JUnit5 and the tests should be inside the project itself, so either in one of the modules or with a separate module that is also included and has some other modules as dependencies.
When I create a separate module with normal JUnit5 tests for it, these Tests get automatically executed in Step 1. So what I want to achieve is a custom gradle step for these system tests.
A good way to do so would be to implement a new gradle task and a new source set with the same name - for example "systemTest". Here is the sample code for a multi module gradle project that has a simple system test:
my file hierarchy:
├── application
│ ├── build.gradle
│ └── src
│ ├── main
│ │ └── java
│ │ └── de
│ │ └── mycompany
│ │ └── mydepartment
│ │ └── projectname
│ │ └── Application.java
│ └── test
│ └── java
│ └── de
│ └── mycompany
│ └── mydepartment
│ └── projectname
│ └── ApplicationTest.java
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── Jenkinsfile
├── settings.gradle
└── systemtests
├── build.gradle
└── src
└── systemTest
└── java
└── de
└── mycompany
└── mydepartment
└── projectname
└── SystemTest.java
Application.java contains my business logic (that should shomehow deploy an application to docker or whatever).
ApplicationTest.java is a JUnit5 unit test that will be run during the build process.
SystemTest.java is a JUnit5 test that is intended to be run after a deployment. We can do this (manually or automatically if the command is added into a build script) via ./gradlew systemTest
.
Now let's look at the gradle files:
build.gradle (root):
subprojects {
apply plugin: 'java'
repositories {
maven {
name 'Nexus-Internal Access'
url 'http://m2repo.system.local/content/groups/full/'
}
}
dependencies {
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.6.0'
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.6.0'
}
sourceSets {
main {
java { output.resourcesDir = outputDir }
}
test {
java { output.resourcesDir = outputDir }
}
}
test {
useJUnitPlatform()
}
}
settings.gradle (root):
rootProject.name = 'service'
include 'application'
include 'systemtests'
application/build.gradle:
apply plugin: 'application'
application {
mainClassName = 'de.mycompany.mydepartment.projectname.Application'
}
systemtests/build.gradle:
configurations {
systemTestImplementation.extendsFrom testImplementation
}
sourceSets {
systemTest {
java { output.resourcesDir = outputDir }
}
jar.duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
task systemTest(type: Test) {
useJUnitPlatform()
group = 'verification'
testClassesDirs = sourceSets.systemTest.output.classesDirs
classpath = sourceSets.systemTest.runtimeClasspath
}
Jenkinsfile (untested phrases for your inspiration):
#!groovy
node {
stage("Build") {
sh """
./gradlew clean build
"""
}
stage("Build docker containers") {
sh """
docker build application
"""
}
stage("Deploy to pre-prod") {
sh """
oc rollout application to testserver
"""
}
stage("System Tests") {
sh """
./gradlew clean systemTest --info
"""
}
stage("Deploy to prod") {
sh """
oc rollout application to prod
"""
}
}
Note that I use --info
on the /gradlew systemTest
task so that I can read logs coming from the system test in the Jenkins Console. I am also using system properties to pass some credentials from our Jenkins into gradle. with another -Pname=${var}
parameter for the systemTest task. Omitted here so that nobody gets confused :)