运行测试

预计阅读时间:7分钟

先决条件

完成“使用容器进行开发”中的步骤来构建映像并将其作为容器化应用程序运行。

介绍

测试是现代软件开发的重要组成部分。对于不同的开发团队来说,测试可能意味着很多事情。有单元测试,集成测试和端到端测试。在本指南中,我们将介绍如何在Docker中运行您的单元测试。

重构Dockerfile以运行测试

春季宠物诊所的源代码已经测试在测试目录中定义src/test/java/org/springframework/samples/petclinic。您只需更新您的JaCoCo版本,pom.xml以确保您的测试可通过结合在JDK v15或更高版本上使用<jacoco.version>0.8.6</jacoco.version>,因此我们可以使用以下Docker命令来启动容器并运行测试:

$ docker run -it --rm --name springboot-test java-docker ./mvnw test
...
[INFO] Results:
[INFO]
[WARNING] Tests run: 40, Failures: 0, Errors: 0, Skipped: 1
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:49 min

用于测试的多阶段Dockerfile

让我们看一下将测试命令拖入我们的Dockerfile中。下面是一个多阶段Dockerfile,我们将使用它来构建生产映像和测试映像。将突出显示的行添加到您的Dockerfile中

# syntax=docker/dockerfile:1

FROM openjdk:16-alpine3.13 as base

WORKDIR /app

COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:go-offline
COPY src ./src

FROM base as test
CMD ["./mvnw", "test"]

FROM base as development
CMD ["./mvnw", "spring-boot:run", "-Dspring-boot.run.profiles=mysql", "-Dspring-boot.run.jvmArguments='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000'"]

FROM base as build
RUN ./mvnw package

FROM openjdk:11-jre-slim as production
EXPOSE 8080

COPY --from=build /app/target/spring-petclinic-*.jar /spring-petclinic.jar

CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/spring-petclinic.jar"]

我们首先在FROM openjdk:16-alpine3.13语句中添加标签。这使我们可以在其他构建阶段中引用此构建阶段。接下来,我们添加了一个名为的新构建阶段test。我们将使用此阶段来运行我们的测试。

现在,让我们重建图像并运行测试。我们将docker build如上所述运行命令,但是这次我们将添加--target test标志,以便我们专门运行测试构建阶段。

$ docker build -t java-docker --target test .
[+] Building 0.7s (6/6) FINISHED
...
 => => writing image sha256:967ac80cb7799a5d12a4bdfc67c37b5a6533c6e418c903907d3e86b7d4ebf89a
 => => naming to docker.io/library/java-docker

现在我们的测试映像已构建,我们可以将其作为容器运行,并查看我们的测试是否通过。

$ docker run -it --rm --name springboot-test java-docker
[INFO] Scanning for projects...
[INFO]
[INFO] ------------< org.springframework.samples:spring-petclinic >------------
[INFO] Building petclinic 2.4.2
...

[INFO] Results:
[INFO]
[WARNING] Tests run: 40, Failures: 0, Errors: 0, Skipped: 1
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:22 min

构建输出被截断,但是您可以看到Maven测试运行程序成功完成并且我们所有的测试都通过了。

这很棒。但是,我们必须运行两个Docker命令来构建和运行我们的测试。我们可以通过使用RUN语句而不是CMD测试阶段中的语句来稍微改进一下。该CMD语句在构建映像期间不会执行,但是在容器中运行该映像时会执行。使用该RUN语句时,我们的测试将在构建映像时运行,并在它们失败时停止构建。

用下面突出显示的行更新您的Dockerfile。

# syntax=docker/dockerfile:1

FROM openjdk:16-alpine3.13 as base

WORKDIR /app

COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:go-offline
COPY src ./src

FROM base as test
RUN ["./mvnw", "test"]

FROM base as development
CMD ["./mvnw", "spring-boot:run", "-Dspring-boot.run.profiles=mysql", "-Dspring-boot.run.jvmArguments='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000'"]

FROM base as build
RUN ./mvnw package

FROM openjdk:11-jre-slim as production
EXPOSE 8080

COPY --from=build /app/target/spring-petclinic-*.jar /spring-petclinic.jar

CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/spring-petclinic.jar"]

现在,要运行测试,我们只需要运行上述docker build命令即可。

$ docker build -t java-docker --target test .
[+] Building 27.6s (11/12)
 => CACHED [base 3/6] COPY .mvn/ .mvn
 => CACHED [base 4/6] COPY mvnw pom.xml ./
 => CACHED [base 5/6] RUN ./mvnw dependency:go-offline
 => CACHED [base 6/6] COPY src ./src
 => [test 1/1] RUN ["./mvnw", "test", "-Dspring-boot.run.profiles=mysql"]
 => exporting to image
 => => exporting layers
=> => writing image sha256:10cb585a7f289a04539e95d583ae97bcf8725959a6bd32c2f5632d0e7c1d16a0
=> => naming to docker.io/library/java-docker

为了简化起见,构建输出被截断了,但是您可以看到我们的测试成功运行并通过了。让我们中断其中一项测试,并在测试失败时观察输出。

打开src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java文件并将第57行更改为以下内容。

55   ConstraintViolation<Person> violation = constraintViolations.iterator().next();
57   assertThat(violation.getPropertyPath().toString()).isEqualTo("firstName");
57   assertThat(violation.getMessage()).isEqualTo("must be empty");
58 }

现在,docker build从上方运行命令,观察构建失败,并将失败的测试信息打印到控制台。

$ docker build -t java-docker --target test .
 => [base 6/6] COPY src ./src
 => ERROR [test 1/1] RUN ["./mvnw", "test", "-Dspring-boot.run.profiles=mysql"]
...
------
executor failed running [./mvnw test]: exit code: 1

多阶段Dockerfile进行开发

新版本的Dockerfile会生成一个最终的图像,该图像已准备好用于生产,但是您会注意到,您还有一个专门的步骤来生产开发容器。

FROM base as development
CMD ["./mvnw", "spring-boot:run", "-Dspring-boot.run.profiles=mysql", "-Dspring-boot.run.jvmArguments='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000'"]

现在,我们可以更新docker-compose.dev.yml该更新,以使用此特定目标来构建petclinic服务并删除command定义,如下所示:

services:
 petclinic:
   build:
     context: .
     target: development
   ports:
     - 8000:8000
     - 8080:8080
   environment:
     - SERVER_PORT=8080
     - MYSQL_URL=jdbc:mysql://mysqlserver/petclinic
   volumes:
     - ./:/app

现在,让我们运行Compose应用程序。现在,您应该看到该应用程序的行为与以前相同,并且您仍然可以对其进行调试。

$ docker-compose -f docker-compose.dev.yml up --build

下一步

在本模块中,我们将运行测试作为Docker映像构建过程的一部分进行了介绍。

在下一个模块中,我们将看一下如何使用GitHub Actions建立CI / CD管道。看:

配置CI / CD

反馈

通过提供您的反馈帮助我们改善此主题。通过在Docker Docs GitHub存储库中创建问题,让我们知道您的想法。或者,创建PR以建议更新。


Java构建测试