Com o advento do .Net Core, temos uma grande oportunidade de não apenas executar nosso código em diferentes sistemas operacionais, mas também testá-lo em diferentes sistemas operacionais. E o que poderia ser melhor que o Docker ao trabalhar com sistemas operacionais diferentes?

O teste é mais valioso quando você não tem diferença entre o ambiente de teste e os ambientes de destino. Imagine que você suporta seu aplicativo em vários sistemas operacionais ou versões de um sistema operacional. Com o Docker, você pode testar seu aplicativo em cada um deles.
Neste artigo, veremos como criar uma imagem separada na qual os testes de unidade do seu aplicativo serão iniciados e configurados para todo esse pipeline de CI / CD no VSTS, que é o Azure DevOps recentemente.
Se você trabalha com o Docker, provavelmente está usando compilações de vários estágios para criar seus contêineres. Nesse caso, você combina a criação de binários (usando a imagem de construção) e a criação da imagem final (usando a imagem de tempo de execução) no mesmo arquivo do Docker.
Se o seu sistema consistir em um contêiner, nesse caso, a abordagem mais comum pode ser executar testes como parte do processo de construção da imagem final. Ou seja, executando testes no Dockerfile.
Para fazer isso em um processo de várias etapas, ao iniciar a
docker build
execute os testes como outra etapa na criação da imagem final. Vejamos um exemplo simples. Digamos que temos dois projetos: aplicativos da web e testes de unidade:
Por enquanto, não vamos nos preocupar com o que o aplicativo da web faz. Por outro lado, temos o único teste que verifica o comportamento do
GuidProvider
e fica assim:
[Fact] public void Never_return_a_empty_guid() {
Agora crie um Dockerfile que criará a imagem WebApplication e executará os testes ao mesmo tempo:
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"]
Este Dockerfile deve ser colocado em um diretório com um arquivo de solução (iCd.sln). Para criar uma imagem, use o comando:
docker build -t webapplication .
Nosso teste falha (um erro no
GuidProvider
que sempre retorna
Guid.Empty
); portanto, a criação da imagem falhará:
saída 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
Agora vamos ver como iniciar esse processo no Azure DevOps.
Nossa definição de compilação no momento é uma tarefa do tipo Docker:

Como resultado do lançamento, a construção falha porque nosso teste cai. Além disso, não temos resultados de teste (a guia "Teste" está vazia), pois o teste não é realizado no entendimento do VSTS:

A execução de testes como parte de um conjunto de imagens não é totalmente ruim, mas impedirá o VSTS de saber qual foi o resultado. Isso ocorre devido à “limitação” do Docker, que não permite a criação de volumes durante a
docker build
, portanto, não podemos fornecer um arquivo com resultados de teste (que podem ser gerados usando o
dotnet test
), esse arquivo permanece em um contêiner intermediário e não é possível obtê-lo facilmente ele de lá.
Adotaremos uma abordagem diferente e usaremos uma ótima alternativa para
docker run
. Primeiro, vamos criar um contêiner separado e executar os testes nele. Para os dois contêineres, podemos usar o mesmo Dockerfile. Antes de tudo, precisamos remover a linha que executa o
dotnet test
do Dockerfile, já que agora os executaremos separadamente. Ok, agora vamos usar o
docker run
, que permite executar o Dockerfile em um ponto específico. No nosso caso, esta é a fase de teste:
docker build -t webapplication-tests . --target test
O parâmetro
-target
indica qual estágio montar. Observe que a imagem gerada será chamada "
webapplication-tests ". Agora podemos executar nossos testes e salvar o arquivo "
test-results.trx " com os resultados de sua execução no diretório "
tests " do contêiner:
docker run -v/c/tests:/tests webapplication-tests --entrypoint "dotnet test --logger trx;LogFileName=/tests/test-results.trx"
Aqui, executamos a imagem criada na etapa anterior e, por meio disso, mapeamos o diretório "
tests " do contêiner para o diretório host (no meu caso, D: \ CiCD \ tests). Como resultado, obtive resultados de testes em D: \ CiCD \ tests.
Para criar a imagem final, execute:
docker build -t webapplication .
A vantagem é que, graças ao modelo de nível do Docker, não é necessário executar novamente todas as outras etapas (ou seja, não é necessário recompilar o aplicativo).
Bem, agora vamos aplicar tudo isso aos pipelines do Azure DevOps. Para simplificar a montagem e evitar um grande número de parâmetros, usaremos o docker-compose. Nosso docker-compose.yml possui o seguinte conteúdo:
version: '3.5' services: webapplication: image: webapplication build: context: . dockerfile: Dockerfile webapplication-tests: image: webapplication-tests build: context: . dockerfile: Dockerfile target: test
Aqui, definimos duas imagens (webapplication e webapplication-tests). Para que tudo esteja de acordo com o cânon, vamos adicionar o arquivo 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
Ótimo, agora para executar os testes, precisamos apenas:
docker-compose run webapplication-tests
Este comando executa os testes e cria o arquivo trx de saída no diretório especificado pela variável de ambiente
BUILD_ARTIFACTSTAGINGDIRECTORY
ou o valor padrão
./tests
. A imagem final é feita assim:
docker-compose build webapplication
Agora você pode editar nosso processo de IC no Azure DevOps. Para fazer isso, definimos as seguintes etapas:
- Colete todas as imagens [build]
- Executar testes de unidade [executar]
- Publicar resultado do teste [publicar]
- Executar imagens no repositório (Registro) [push]
Vamos começar com a primeira etapa, que é a tarefa Docker Compose (tarefa) no Azure:

Colocamos
Action: Build service images
e especificamos o caminho para o docker-compose.yml.
Em seguida, execute o contêiner com testes de unidade:

Aqui você precisa selecionar
Action: Run a specific service image
e especificar o nome do contêiner Nome do
Service Name: webapplication-tests
. Além disso, não esqueça o caminho para o docker-compose.yml e o docker-compose.override.yml. O valor para
Run in Background
Segundo
Run in Background
não deve ser definido, caso contrário, o contêiner iniciará no "Modo Desconectado" e a tarefa não aguardará os resultados dos testes e passará para a próxima etapa. A tarefa Publicar Resultados do Teste tentará publicar resultados que ainda não estão disponíveis, pois a execução de testes leva tempo.
A terceira etapa é "Publicar resultados do teste":
É importante especificar
Run this task: Even if a previous task has failed, unless the build was canceled
. Essa opção é importante porque, caso contrário, os resultados nunca serão publicados se os testes falharem.
Search folder: $(Build.ArtifactStagingDirectory)
O passo final será colocar as imagens no armazenamento. Para fazer isso, especifique a assinatura do Azure, bem como o Registro de Contêiner do Azure. Tudo está pronto para criar uma nova compilação. Salve. Começamos. Se os testes falharem, a construção falhará, mas agora vemos os resultados no VSTS:

Espero que este material tenha sido útil. Você pode encontrar meu arquivo yml de configuração de montagem
aqui .
Obrigado pela atenção!