我们有一个Spring Boot应用程序,其中包含6个不同的模块,其中一个模块包含对前端部分的黄瓜测试。前端部分是使用百里香框架创建的。 我们的应用程序是使用jenkins管道部署在jenkins上的。进行部署时,我们使用docker容器来部署应用程序的战争,并使用另一个docker容器运行黄瓜测试。 对于该应用程序,我们尝试使用jacoco maven插件针对所有5个模块的所有Java类运行黄瓜测试后,生成覆盖报告。为了获得覆盖范围,我们在jenkins管道的发布步骤中尝试生成报告。 问题在于此覆盖范围不够完整,因为仅覆盖了黄瓜测试模块。如果有一种解决方案可以从所有模块生成所有类的覆盖范围,我们将很感兴趣。
请参阅下面的jenkins管道:
pipeline {
agent any
environment {
MAVEN_JDK_IMAGE = 'maven:3.6.3-jdk-11'
NETWORK = 'test'
NETWORK_SUBNET = '172.18.0.0/16'
WEBAPP_IP = '172.18.0.10'
}
stages {
stage("Prepare environment") {
steps {
sh 'docker ps -f name=${DB_CONTAINER_NAME} -q | xargs --no-run-if-empty docker container stop'
sh 'docker container ls -a -fname=${DB_CONTAINER_NAME} -q | xargs -r docker container rm'
sh 'docker ps -f name=${WEBAPP_CONTAINER_NAME} -q | xargs --no-run-if-empty docker container stop'
sh 'docker container ls -a -fname=${WEBAPP_CONTAINER_NAME} -q | xargs -r docker container rm'
sh 'docker ps -f name=${SELENIUM_CONTAINER_NAME} -q | xargs --no-run-if-empty docker container stop'
sh 'docker container ls -a -fname=${SELENIUM_CONTAINER_NAME} -q | xargs -r docker container rm'
sh 'docker ps -f name=${GREENMAIL_CONTAINER_NAME} -q | xargs --no-run-if-empty docker container stop'
sh 'docker container ls -a -fname=${GREENMAIL_CONTAINER_NAME} -q | xargs -r docker container rm'
sh 'docker ps -f network=${NETWORK} -q | xargs --no-run-if-empty docker container stop'
sh 'docker container ls -a -f network=${NETWORK} -q | xargs -r docker container rm'
sh 'docker network ls -f name=${NETWORK} -q | xargs --no-run-if-empty docker network rm'
sh 'docker network create --subnet=${NETWORK_SUBNET} ${NETWORK}'
}
}
stage('Build project') {
steps {
script{
docker.image('${MAVEN_JDK_IMAGE}').inside('-v /root/.m2:/root/.m2 --net ${NETWORK}'){
sh 'mvn clean install -DskipTests'
}
}
}
}
stage('Docker Build and Generate Database') {
steps {
sh 'docker build -t db_pg_tests_ui:${APP_VERSION} -t ${DOCKER_DB_IMAGE_NAME}:${APP_VERSION} -f Dockerfile_DB_Tests_UI .'
sh 'docker push ${DOCKER_DB_IMAGE_NAME}:${APP_VERSION}'
}
}
stage('Docker Build WebApp') {
steps {
sh 'mkdir -p ./tmp'
sh 'cp ./${SECURITY}/target/${SECURITY}.war ./tmp'
sh 'cp ./${PAYER}-ui/target/${PAYER}.war ./tmp'
sh 'cp ./${REFERRER}-ui/target/${REFERRER}.war ./tmp'
sh 'cp ./${MANAGEMENT}-ui/target/${MANAGEMENT}.war ./tmp'
sh 'cp ./${CARE_INSTITUTION}-ui/target/${CARE_INSTITUTION}.war ./tmp'
sh 'docker build -t webapp_test_ui:${APP_VERSION} -t ${DOCKER_WEBAPP_IMAGE_NAME}:${APP_VERSION} -f Dockerfile_WebApp_Tests_UI .'
sh 'docker push ${DOCKER_WEBAPP_IMAGE_NAME}:${APP_VERSION}'
}
}
stage('Deploy GreenMail') {
steps {
echo 'Now deploy tests_UI Greenmail'
script {
def mailImage = docker.image('greenmail/standalone:1.5.13')
mailImage.pull()
mailImage.run('-t -i -p ${PORT_SMTP}:3025 --name ${GREENMAIL_CONTAINER_NAME} --net ${NETWORK}')
MAIL_IP = sh(script: 'docker inspect --format=\'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}\' ${GREENMAIL_CONTAINER_NAME}', returnStdout: true).trim()
echo MAIL_IP
}
echo 'Successfully deployed tests_UI GreenMail'
}
}
stage('Deploy DB') {
steps {
echo 'Now deploy tests_UI DB'
script {
def dbImage = docker.image('${DOCKER_DB_IMAGE_NAME}:${APP_VERSION}')
dbImage.pull()
dbImage.run('-p ${PORT_DB}:5432/TCP/IP -i -t --name ${DB_CONTAINER_NAME} --net ${NETWORK}')
DB_IP = sh(script: 'docker inspect --format=\'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}\' ${DB_CONTAINER_NAME}', returnStdout: true).trim()
echo DB_IP
}
echo 'Successfully deployed tests_UI DB'
}
}
stage('Deploy WEBAPP') {
environment {
DB_IP = "${DB_IP}"
MAIL_IP = "${MAIL_IP}"
}
steps {
echo 'Now deploy webapp'
script {
def webImage = docker.image('${DOCKER_WEBAPP_IMAGE_NAME}:${APP_VERSION}')
webImage.pull()
webImage.run('-p ${PORT_WEBAPP}:8080 -i -t -e DATABASE_IP=${DB_IP} -e MAIL_IP=${MAIL_IP} -e PORT_SMTP=${PORT_SMTP} -e default.locale=de-DE --name ${WEBAPP_CONTAINER_NAME} --net ${NETWORK} --ip ${WEBAPP_IP}')
echo 'Wait for app to deploy all 5 modules'
docker.script.sh(script: 'sleep 100', returnStdout: true)
}
echo 'Successfully deployed webapp for UI tests'
}
}
stage('Docker build selenium image') {
steps {
sh 'docker build -t ${SELENIUM_IMAGE_NAME}:${APP_VERSION} -t ${REPOSITORY}${SELENIUM_IMAGE_NAME}:${APP_VERSION} -f Dockerfile_Cucumber_Tests_UI .'
sh 'docker push ${REPOSITORY}${SELENIUM_IMAGE_NAME}:${APP_VERSION}'
}
}
stage('Deploy Selenium') {
steps {
script {
def seleniumImage = docker.image('${REPOSITORY}${SELENIUM_IMAGE_NAME}:${APP_VERSION}')
seleniumImage.pull()
seleniumImage.run('-p ${PORT_SELENIUM}:4444 -i -t --name ${SELENIUM_CONTAINER_NAME} --net ${NETWORK}')
}
echo 'Successfully deployed Selenium for UI tests'
}
}
stage('Find webapp and selenium IP\'s') {
steps {
script {
DOCKER_WEBAPP_IP = sh(script: 'docker inspect --format=\'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}\' ${WEBAPP_CONTAINER_NAME}', returnStdout: true).trim()
echo DOCKER_WEBAPP_IP
SELENIUM_IP = sh(script: 'docker inspect --format=\'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}\' ${SELENIUM_CONTAINER_NAME}', returnStdout: true).trim()
echo SELENIUM_IP
}
}
}
stage('Running UI Tests') {
environment {
DB_IP = "${DB_IP}"
WEBDRIVER_URL = "http://${SELENIUM_IP}:4444/wd/hub/"
PAYER_URL = "http://${DOCKER_WEBAPP_IP}:8080/payer"
CARE_INSTITUTION_URL = "http://${DOCKER_WEBAPP_IP}:8080/care-institution"
REFERRER_URL = "http://${DOCKER_WEBAPP_IP}:8080/referrer"
LOGIN_URL = "http://${DOCKER_WEBAPP_IP}:8080/security"
}
steps {
script {
def mavenImage = docker.image('${MAVEN_JDK_IMAGE}')
mavenImage.pull()
mavenImage.inside('-v /root/.m2:/root/.m2 -e default.locale=de-DE --net ${NETWORK}') {
echo 'Starts UI Cucumber tests'
sh 'cd specifications && mvn test -Pdocker-UI-Tests -fae -DDATABASE_IP=${DB_IP} -Dshareddriver.remote.url="${WEBDRIVER_URL}" -Dshareddriver.payer.url="${PAYER_URL}" -Dshareddriver.careinstitution.url="${CARE_INSTITUTION_URL}" -Dshareddriver.referrer.url="${REFERRER_URL}" -Dshareddriver.login.url="${LOGIN_URL}" -Dcucumber.options="--tags ~@onlyLocally"'
echo 'Successfully run UI tests'
}
}
}
}
}
post {
always {
sh 'docker ps -f name=${WEBAPP_CONTAINER_NAME} -q | xargs --no-run-if-empty docker container stop'
sh 'docker container ls -a -fname=${WEBAPP_CONTAINER_NAME} -q | xargs -r docker container rm'
sh 'docker ps -f name=${DB_CONTAINER_NAME} -q | xargs --no-run-if-empty docker container stop'
sh 'docker container ls -a -fname=${DB_CONTAINER_NAME} -q | xargs -r docker container rm'
sh 'docker ps -f name=${GREENMAIL_CONTAINER_NAME} -q | xargs --no-run-if-empty docker container stop'
sh 'docker container ls -a -fname=${GREENMAIL_CONTAINER_NAME} -q | xargs -r docker container rm'
sh 'docker ps -f name=${SELENIUM_CONTAINER_NAME} -q | xargs --no-run-if-empty docker container stop'
sh 'docker container ls -a -fname=${SELENIUM_CONTAINER_NAME} -q | xargs -r docker container rm'
cucumber buildStatus: 'UNSTABLE',
fileIncludePattern: '**/cucumber-json-report/**/*.json',
trendsLimit: 15,
sortingMethod: 'NATURAL',
classifications: [
['key': 'Browser', 'value': 'Chrome']
]
script {
junit '**/surefire-reports/**/*.xml'
}
step([$class: 'JacocoPublisher',
execPattern: '**/coverage-reports/*.exec'
])
}
success {
echo 'Build finished successfully'
}
}
}
另外,用于在詹金斯上进行黄瓜测试的maven配置文件:
<profile>
<id>docker-UI-Tests</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>false</skip>
<argLine>-Dspring.profiles.active=docker-UI-Tests @{jacocoArg}</argLine>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<skip>false</skip>
<argLine>-Dspring.profiles.active=docker-UI-Tests @{jacocoArg}</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${project.build.directory}/coverage-reports/jacoco.exec</destFile>
<propertyName>jacocoArg</propertyName>
</configuration>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/coverage-reports/jacoco.exec</dataFile>
<outputDirectory>${project.reporting.outputDirectory}/jacoco</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
谢谢您的任何建议,
Dănuț!