首页 > 解决方案 > 如果我想在发布管道中运行它们,我应该在构建管道中的测试项目上运行 dotnet publish 吗?

问题描述

我的存储库中有一些集成和 ui 测试项目 (*.csproj)。

我知道我需要发布测试程序集来构建工件,以便稍后在发布管道中运行它们。

我的问题是:

我应该如何拾取测试组件?

  1. 从构建输出
  2. 或者应该运行dotnet publish tests/MyE2ETests.csproj --output $(Build.ArtifactStagingDirectory)/tests

请参阅此构建管道的最后一步

- 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'

标签: asp.net-core.net-coreazure-devopsmsbuildazure-pipelines

解决方案


我使用一个简单的 CopyTask 将单元测试构建输出复制到暂存文件夹。重要的是设置flattenFolders = false(默认)以保留文件夹结构,因为构建输出包含位于不同位置的 Nuget 包,dotnet test 在运行时将查找这些包。

.NET Core+ 中的构建输出是一个深度嵌套的文件夹结构。因此,我创建了一个在文件夹结构中搜索单元测试 dll 并返回包含文件夹路径的模板。我将它存储在一个变量resultfolder中。这种方法删除了文件夹结构的上层,因此您可以下载一个干净的工件。

#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'

查找包含文件夹.yml 模板:

# 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
        }

推荐阅读