1

I am trying to run my Automation "Specflow+ Runner" C# Test Cases using docker. I have a master.yml file which uses the Shared Agent and it builds docker image using Dockerfile.

master.yml

jobs:
  - job: run_docker_build
    displayName: Run UI Build
    steps:
#------------------------------------------
# Build Docker
#------------------------------------------
      - task: Docker@2
        displayName: DockerBuild
        env:
         COMPOSE_DOCKER_CLI_BUILD: 1
         DOCKER_BUILDKIT: 1
        inputs:
         containerRegistry: "XXX"
         repository: run-automation-ui
         command: build
         Dockerfile: '**/Dockerfile'
         tags: |
          latest
          $(Build.BuildId)

#------------------------------------------
# Copy the Results from Build Image
#------------------------------------------
      - pwsh: |
         $id=docker images --filter "label=Test=True" -q | Select-Object -First 1
         docker create --name testcontainer $id
         docker cp testcontainer:/src/AutomationTests/TestResults ./TestResults
         docker cp testcontainer:/src/AutomationTests/TestResults/Screenshots ./Screenshots
         docker rm testcontainer
        displayName: 'Copy Test Results'
        condition: always()
#------------------------------------------
# Publishing Test Results
#------------------------------------------
      - task: PublishTestResults@2
        inputs:
         testResultsFormat: 'VSTest'
         testResultsFiles: '**/*.trx'
         searchFolder: '$(System.DefaultWorkingDirectory)/TestResults'
         publishRunAttachments: true
        displayName: 'Publish Test Results' 
        condition: always()

Docker File

LABEL Test=True
##Method one (#Even if test fails the build task will finish and in later stage I can copy the Results ) 
#RUN dotnet test -c Release --no-build --logger "trx;LogFileName=/src/AutomationTests/TestResults/test_results.trx" --filter TestCategory=DockerTest || true 

#Method Two (#Even if test fails the build task will finish and in later stage I can copy the Results )
#RUN dotnet test -c Release --no-build --logger "trx;LogFileName=/src/AutomationTests/TestResults/test_results.trx" --filter TestCategory=DockerTest; exit 0 

#Method Three (#Even if test fails the build task will finish and in later stage I can copy the Results )
#RUN dotnet test -c Release --no-build --logger "trx;LogFileName=/src/AutomationTests/TestResults/test_results.trx" --filter TestCategory=DockerTest; \
#echo $? > /dotnet.exitcode;
#RUN exit $(cat /dotnet.exitcode)

#Method Four (if test fails means still i need to able to copy the results )
#RUN dotnet test -c Release --no-build --logger "trx;LogFileName=/src/AutomationTests/TestResults/test_results.trx" --filter TestCategory=DockerTest

I am looking how can I copy my results if any Tests failed in Dockerfile means

1 Answers1

4

Rather than running dotnet test in a RUN instruction, you can define it as an ENTRYPOINT so that whenever you execute the container, it runs the tests. That integrates the exit code behavior directly with the running of the container.

This can be done with a multi-stage Dockerfile, dedicating a specific stage for testing purposes.

Here's an example Dockerfile taken from that demonstrates this pattern (taken from https://github.com/dotnet/dotnet-docker/blob/e576a1e988bc9320ba971866b01404f4d040afb7/samples/complexapp/Dockerfile):

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /source

# copy csproj and restore as distinct layers
COPY complexapp/*.csproj complexapp/
COPY libfoo/*.csproj libfoo/
COPY libbar/*.csproj libbar/
RUN dotnet restore complexapp/complexapp.csproj

# copy and build app and libraries
COPY complexapp/ complexapp/
COPY libfoo/ libfoo/
COPY libbar/ libbar/
WORKDIR /source/complexapp
RUN dotnet build -c release --no-restore

# test stage -- exposes optional entrypoint
# target entrypoint with: docker build --target test
FROM build AS test
WORKDIR /source/tests

COPY tests/*.csproj .
RUN dotnet restore tests.csproj

COPY tests/ .
RUN dotnet build --no-restore

ENTRYPOINT ["dotnet", "test", "--logger:trx", "--no-restore", "--no-build"]

FROM build AS publish
RUN dotnet publish -c release --no-build -o /app

# final stage/image
FROM mcr.microsoft.com/dotnet/runtime:6.0
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "complexapp.dll"]

To use this test stage, you would first need to run docker build, targeting that specific stage:

docker build --target test -t tester .

When you run the container, you can volume mount a path from the host to the container so that you can have access to the test results. Here's an example using the paths you indicated in your question:

docker run --rm -v $(System.DefaultWorkingDirectory)/TestResults:/src/AutomationTests/TestResults tester
Matt Thalman
  • 3,540
  • 17
  • 26
  • Thank you very much for your Answer. I tried exactly as you Mentioned with Multi Stages.I Kept 3 different Stages in my Dockerfile **restore**, **build** and **test**. From my master.yml I am calling docker build --target restore -t tester . && docker build --target build -t tester . && docker build --target test -t tester . (I made 1 Test to fail) Next I am calling docker run --rm -v $(System.DefaultWorkingDirectory)/TestResults:/src/AutomationTests/TestResults tester When I added Task powershell task $fileExists = Test-Path -Path "$(System.DefaultWorkingDirectory)/TestResults/*" (False) – srikanth reddy karumuri Aug 06 '22 at 20:21
  • Dockerfile `code FROM mcr.microsoft.com/dotnet/sdk:5.0 AS base WORKDIR /AutomationTests COPY /AutomationTests /AutomationTests/AutomationTests/ WORKDIR /AutomationTests/AutomationTests From base AS restore RUN dotnet restore "AutomationTests.csproj" --configfile "nuget.config" FROM restore AS build RUN dotnet build -c Release --no-restore FROM build AS test LABEL Test=True RUN dotnet test -c Release --no-build --logger "trx;LogFileName=test_results.trx" --filter TestCategory=DockerTest ` – srikanth reddy karumuri Aug 06 '22 at 20:30
  • Master.yml **One** `code steps: - script: | docker build -f **/Dockerfile --target restore -t XXX.azurecr.io/automation-ui:$(Build.BuildId) . - script: | docker build -f **/Dockerfile --target build -t XXX.azurecr.io/automation-ui:$(Build.BuildId) . - script: | docker build -f **/Dockerfile --target test -t XXX.azurecr.io/automation-ui:$(Build.BuildId) . ` – srikanth reddy karumuri Aug 06 '22 at 20:41
  • Master.yml **Two** `code - script: | docker run --rm -v $(System.DefaultWorkingDirectory)/TestResults:/AutomationTests/AutomationTests/TestResults XXX.azurecr.io/automation-ui:$(Build.BuildId) docker run --rm -v $(System.DefaultWorkingDirectory)/Screenshots:/AutomationTests/AutomationTests/TestResults/Screenshots XXX.azurecr.io/automation-ui:$(Build.BuildId) ` – srikanth reddy karumuri Aug 06 '22 at 20:44
  • What I have noticed is as 1 of the Test is failing below steps are not happening `code #13 exporting to image #13 sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx #13 exporting layers #13 exporting layers 0.1s done #13 writing image sha256:xxxxxxxxxxxxxxxxxxxxx done #13 naming to docker.io/library/automation-ui-1749927 done #13 DONE 0.1s Finishing: test ` – srikanth reddy karumuri Aug 07 '22 at 15:48
  • Thanks a lot @Matt your solution worked perfectly. Initially I misunderstood you answer and did it in a wrong away. After going through your steps carefully I did it correctly. In process I have learnt a lot. Once again thanks a lot. -v (volume) worked perfectly. – srikanth reddy karumuri Aug 14 '22 at 20:41
  • Good to hear. Please mark this as an answer. – Matt Thalman Aug 15 '22 at 13:34