3

I have some integration and ui test projects (*.csproj) in my repository.

I understand I need to publish the test assemblies to build artifacts in order to run them later in Release pipeline.

My question is:

How should I pickup the test assemlies?

  1. from a build output
  2. or should run dotnet publish tests/MyE2ETests.csproj --output $(Build.ArtifactStagingDirectory)/tests

See last step of this build pipeline

- task: DotNetCoreCLI@2
  displayName: 'dotnet build $(buildConfiguration)'
  inputs:
    command: 'build'
    arguments: '--configuration $(buildConfiguration)'


- task: DotNetCoreCLI@2
  displayName: 'dotnet publish web app'
  inputs:
    command: publish
    publishWebProjects: True
    arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)/app'
    zipAfterPublish: True

- task: PublishBuildArtifacts@1
  displayName: 'Publish web app artifacts'
  inputs:
    pathtoPublish: '$(Build.ArtifactStagingDirectory)/app' 
    artifactName: 'App'

- task: PublishBuildArtifacts@1
  displayName: 'Publish tests artifacts'
  inputs:
    pathtoPublish: ???
    artifactName: 'Tests'
Liero
  • 25,216
  • 29
  • 151
  • 297
  • Hi Liero, I have updated my answer, could you please check it and kindly let me know the result? I am looking forward to hearing from you. Thanks. – Edward Han-MSFT Mar 30 '21 at 03:28

2 Answers2

1

If you create a build pipeline and use the following pre-defined ASP.NET Core template, enter image description here you will get the pre-configured build pipeline including DotNet restore step, DotNet build step, DotNet test step, DotNet publish step and then finally publish them as build artifacts, as below. enter image description here See: Build, test, and deploy .NET Core apps for more guidance.

Update>>If you want to run tests in release pipeline, you need to add a copy file to copy *.csproj to $(build.artifactstagingdirectory) and then use publish build artifact task to publish it to artifacts.

- task: CopyFiles@2
  displayName: 'Copy Files to: $(build.artifactstagingdirectory)'
  inputs:
    SourceFolder: '$(Build.SourcesDirectory)'
    Contents: '**/*[Tt]ests/*.csproj'
    TargetFolder: '$(build.artifactstagingdirectory)'
- task: PublishBuildArtifacts@1
  displayName: 'Publish tests artifacts'
  inputs:
    pathtoPublish: '$(Build.ArtifactStagingDirectory)/tests'
    artifactName: 'Tests'
Edward Han-MSFT
  • 2,879
  • 1
  • 4
  • 9
  • The question was about running tests in release pipeline, not in a build pipeline. E.g. E2E tests, Integration Tests, etc. – Liero Mar 25 '21 at 13:38
  • Thanks. Well, obviously I need the test dlls in release pipeline, not just csproj. Actually I don't need .csproj and source code at all. The question is whether I should run just `dotnet build` on the test project and copy build output folder, or I should run `dotnet publish` and copy publish output. – Liero Mar 30 '21 at 07:53
  • Thanks for your reply. If you run just dotnet build on the test project in build pipeline, you need to copy the build output folder. – Edward Han-MSFT Mar 30 '21 at 07:56
  • Well that's what I mentioned in my question. My question still remains unanswered :( – Liero Mar 30 '21 at 07:57
1

I use a simple CopyTask to copy the unit test build output to the staging folder. The important thing is to set flattenFolders = false (default) to preserve the folder structure, since the build output contains Nuget packages in different locations that dotnet test will look for when it is run.

The build output in .NET Core+ is a deeply nested folder structure. Therefore, I have create a template that searches for the unit test dll inside the folder structure and returns the containing folder path. I store it in a variable resultfolder. This approach removes the upper levels of the folder structure so you get a clean artifact to download.

#search bin subfolders to find the content:
- template: ../Tasks/find-containing-folder.yml  # Template reference
  parameters: 
    condition: variables['doUnitTest']
    folderPathToSearch: '$(Build.SourcesDirectory)\${{ parameters.unitTestProjectName }}\bin\Release'
    filename: ${{ parameters.unitTestProjectName }}.dll

- task: CopyFiles@2
  displayName: 'Copy unit test project build output to artifact staging folder'
  condition: eq(variables['doUnitTest'], true)
  inputs:
    sourceFolder: '$(resultfolder)'
    targetFolder: '$(Build.ArtifactStagingDirectory)/UnitTest'

find-containing-folder.yml template:

# returns the full path of the first folder found containing the file.
# returns the result in a variable called resultfolder.
# condition parameter is a workaround because template references don't allow conditions. Also, string has to be used, booleans don't work.
# (this is used to navigate through the target framework and runtime identifier subfolders to find the output.
# the folders are determined by what the csproj file contains.)
parameters:
- name: condition
  type: string 
  default: true

- name: folderPathToSearch
  type: string

- name: filename
  type: string

steps:

- task: PowerShell@2
  displayName: 'Find containing folder'
  condition: eq(${{ parameters.condition }}, true)
  inputs:
    targetType: 'inline'
    script: |
        $folderPath = "${{ parameters.folderPathToSearch }}"
        Write-Host "Searching folder: " $folderPath

        $searchResult = Get-ChildItem -Path $folderPath -Recurse -Filter '${{ parameters.filename }}' -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty Directory

        Write-Host "searchResult: " $searchResult

        if($searchResult -like "*$folderPath*")
        {
        Write-Host "Found build output folder: " $searchResult
        echo "##vso[task.setvariable variable=resultfolder]$searchResult"
        }
        else 
        {
        Write-Host "Build output not found." 
        exit 1
        }
Rye bread
  • 1,305
  • 2
  • 13
  • 36