我们在Azure DevOps(VSTS)中使用单元测试启动容器

随着.Net Core的出现,我们有了巨大的机会,不仅可以在不同的操作系统上运行我们的代码,而且可以在不同的操作系统上对其进行测试。 在使用不同的OS时,还有什么比Docker更好的呢?

如果您在测试环境和目标环境之间没有区别,则测试将更有价值。 假设您在多个操作系统或某个操作系统版本上支持您的应用程序。 使用Docker,您可以在每个应用程序中测试您的应用程序。

在本文中,我们将研究如何创建一个单独的映像,在该映像中将启动应用程序的单元测试,并为VSTS(最近是Azure DevOps)中的所有此CI / CD管道进行配置。

如果您使用Docker,则可能正在使用多阶段构建来构建容器。 在这种情况下,您将在同一Docker文件中将二进制文件的创建(使用构建映像)和最终映像的创建(使用运行时映像)组合在一起。

如果您的系统由一个容器组成,则在这种情况下,最常见的方法可能是在构建最终映像的过程中运行测试。 也就是说,在Dockerfile中运行测试。

要在多步骤过程中执行此操作,请在运行docker build将测试运行为构建最终映像的另一步骤。 让我们看一个简单的例子。 假设我们有两个项目:Web应用程序和单元测试:


现在,让我们不必担心Web应用程序的功能。 另一方面,我们拥有唯一的检查GuidProvider行为的测试,如下所示:

 [Fact] public void Never_return_a_empty_guid() { // Arrange & Act var provider = new GuidProvider(); var id = provider.Id; // Assert Assert.NotEqual(Guid.Empty, id); } 

现在创建一个Dockerfile,该文件将创建WebApplication映像并同时运行测试:

 FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base WORKDIR /app EXPOSE 80 FROM microsoft/dotnet:2.1-sdk AS build WORKDIR /src COPY CiCd.sln . COPY WebApplication/WebApplication.csproj WebApplication/ COPY WebApplication.Test/WebApplication.Test.csproj WebApplication.Test/ RUN dotnet restore COPY . . WORKDIR /src/WebApplication RUN dotnet build --no-restore -c Release -o /app FROM build as test WORKDIR /src/WebApplication.Test RUN dotnet test FROM build AS publish WORKDIR /src/WebApplication RUN dotnet publish --no-build -c Release -o /app FROM base AS final WORKDIR /app COPY --from=publish /app . ENTRYPOINT ["dotnet", "WebApplication.dll"] 

该Dockerfile必须放置在带有解决方案文件(iCd.sln)的目录中。 要创建图像,请使用以下命令:

 docker build -t webapplication . 

我们的测试失败( GuidProvider中的错误始终返回Guid.Empty ),因此映像构建将失败:

输出
 Step 15/22 : RUN dotnet test ---> Running in 423c27696356 Build started, please wait... Build completed. Test run for /src/WebApplication.Test/bin/Debug/netcoreapp2.1/WebApplication.Test.dll(.NETCoreApp,Version=v2.1) Microsoft (R) Test Execution Command Line Tool Version 15.9.0 Copyright (c) Microsoft Corporation. All rights reserved. Starting test execution, please wait... [xUnit.net 00:00:00.96] WebApplication.Test.GuidProviderTests.Never_return_a_empty_guid [FAIL] Failed WebApplication.Test.GuidProviderTests.Never_return_a_empty_guid Error Message: Assert.NotEqual() Failure Expected: Not 00000000-0000-0000-0000-000000000000 Actual: 00000000-0000-0000-0000-000000000000 Stack Trace: at WebApplication.Test.GuidProviderTests.Never_return_a_empty_guid() in /src/WebApplication.Test/GuidProviderTests.cs:line 17 Test Run Failed. Total tests: 1. Passed: 0. Failed: 1. Skipped: 0. Test execution time: 2.8166 Seconds The command '/bin/sh -c dotnet test' returned a non-zero code: 1 

现在,让我们看看如何在Azure DevOps中启动此过程。

目前,我们的构建定义是一项Docker类型任务:



启动的结果是,构建失败,因为我们的测试失败了。 此外,我们没有测试结果(“测试”选项卡为空),因为在理解VSTS时未执行测试:



将测试作为映像程序集的一部分运行并不完全不好,但是它将阻止VSTS知道结果是什么。 这是由于Docker的“局限性”,不允许在docker build期间创建卷,因此我们无法为文件提供测试结果(可以使用dotnet test生成),该文件保留在中间容器中,我们无法轻易获取它他从那里。

我们将采用不同的方法,并使用docker run替代方法。 首先,让我们提出一个单独的容器并在其中运行测试。 对于这两个容器,我们可以使用相同的Dockerfile。 首先,我们需要从Dockerfile中删除运行dotnet test的行,因为现在我们将分别运行它们。 好的,现在让我们使用docker docker run ,它允许您将Dockerfile运行到特定位置。 在我们的例子中,这是测试阶段:

 docker build -t webapplication-tests . --target test 

-target参数指示要组装的平台。 请注意,生成的图像将被称为“ webapplication-tests ”。 现在,我们可以运行测试,并将其执行结果保存在“ tests ”目录中的文件“ test-results.trx ”中:

 docker run -v/c/tests:/tests webapplication-tests --entrypoint "dotnet test --logger trx;LogFileName=/tests/test-results.trx" 

在这里,我们运行在上一步中创建的映像,然后将容器“ tests ”目录映射到主机目录(在我的情况下为D:\ CiCD \ tests)。 结果,我在D:\ CiCD \ tests中获得了测试结果。

为了生成最终映像,请运行:

 docker build -t webapplication . 

优点是,由于使用了Docker级别的模型,因此无需重新执行所有其他步骤(即,无需重新编译应用程序)。

好吧,现在让我们将所有这些应用于Azure DevOps管道。 为了简化组装并避免使用大量参数,我们将使用docker-compose。 我们的docker-compose.yml具有以下内容:

 version: '3.5' services: webapplication: image: webapplication build: context: . dockerfile: Dockerfile webapplication-tests: image: webapplication-tests build: context: . dockerfile: Dockerfile target: test 

在这里,我们定义了两个图像(webapplication和webapplication-tests)。 为了使一切都符合佳能,让我们添加docker-compose.override.yml文件:

 version: '3.5' services: webapplication: environment: - ASPNETCORE_ENVIRONMENT=Development ports: - "8080:80" webapplication-tests: entrypoint: - dotnet - test - --logger - trx;LogFileName=/tests/test-results.trx volumes: - ${BUILD_ARTIFACTSTAGINGDIRECTORY:-./tests/}:/tests 

太好了,现在运行测试,我们只需要:

 docker-compose run webapplication-tests 

此命令运行测试并在环境变量BUILD_ARTIFACTSTAGINGDIRECTORY或使用默认值./tests指定的目录中创建输出trx文件。 最终图像如下所示:

 docker-compose build webapplication 

现在,您可以在Azure DevOps中编辑CI流程。 为此,我们定义以下步骤:

  1. 收集所有图像[构建]
  2. 运行单元测试[运行]
  3. 发布测试结果[发布]
  4. 在存储库(注册表)中运行图像[push]

让我们从第一步开始,这是Azure中的Docker Compose任务(任务):



我们将Action: Build service images并指定docker-compose.yml的路径。

接下来,使用单元测试运行容器:



在这里,您需要选择Action: Run a specific service image并指定容器名称Service Name: webapplication-tests 。 另外,不要忘记docker-compose.yml和docker-compose.override.yml的路径。 不应设置Run in Background ”的值,否则容器将以“分离模式”启动,并且任务将不等待测试结果,而是继续进行下一步。 由于运行测试需要时间,因此“发布测试结果”任务将尝试发布可能尚不可用的结果。

第三步是“发布测试结果”:



指定Run this task: Even if a previous task has failed, unless the build was canceled 很重要 Run this task: Even if a previous task has failed, unless the build was canceled 。 此选项很重要,因为否则,如果测试失败,结果将永远不会发布。 Search folder: $(Build.ArtifactStagingDirectory)

最后一步是将图像推入存储。 为此,请指定Azure订阅以及Azure容器注册表。 一切准备就绪,可以创建新的版本。 保存。 我们开始。 如果测试失败,构建将失败,但是现在我们在VSTS中看到了结果:



我希望该材料对您有所帮助。 您可以在此处找到我的程序集配置yml文件。

感谢您的关注!

Source: https://habr.com/ru/post/zh-CN430958/


All Articles