3

I was able to implement parallel pytesting in Azure CI. See this repo for reference. But still code coverage is not working as expected. It is individually working, but it is not combining all tests coverage.

Here is the Azure config file I am using:

# Python test sample
# Sample that demonstrates how to leverage the parallel jobs capability of Azure Pipelines to run python tests in parallel.
# Parallelizing tests helps in reducing the time spent in testing and can speed up the pipelines significantly.
variables:
  disable.coverage.autogenerate: 'true'

jobs:

- job: 'ParallelTesting'
  pool:
    vmImage: 'windows-latest'
  strategy:
    parallel: 3

  steps:
  - task: UsePythonVersion@0
    inputs:
      versionSpec: '3.7'
      addToPath: true
      architecture: 'x64'

  - script: |
      python -m pip install --upgrade pip setuptools wheel
    displayName: 'Install tools'

  - script: 'pip install -r $(System.DefaultWorkingDirectory)/requirements.txt' 
    displayName: 'Install dependencies'

  - powershell: ./DistributeTests.ps1 
    displayName: 'PowerShell Script to distribute tests'

  - script: |
      pip install pytest-azurepipelines pytest-cov
    displayName: 'Install Pytest dependencies'

  - script: |
      echo $(pytestfiles)
      pytest $(pytestfiles) --junitxml=junit/$(pytestfiles)-results.xml --cov=. --cov-report=xml --cov-report=html
    displayName: 'Pytest'
    continueOnError: true

  - task: PublishTestResults@2
    displayName: 'Publish Test Results **/*-results.xml'
    inputs:
      testResultsFiles: '**/*-results.xml'
      testRunTitle: $(python.version)
    condition: succeededOrFailed()

  - task: PublishCodeCoverageResults@1
    inputs:
      codeCoverageTool: Cobertura
      summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml'
      reportDirectory: '$(System.DefaultWorkingDirectory)/**/htmlcov'
    displayName: 'Publish code coverage results'

And the powershell script to distribute tests:

<#  
.SYNOPSIS  
    Distribute the tests in VSTS pipeline across multiple agents 
.DESCRIPTION  
    This script slices tests files across multiple agents for faster execution.
    We search for specific type of file structure (in this example test*), and slice them according to agent number
    If we encounter multiple files [file1..file10] and if we have 2 agents, agent1 executes tests odd number of files while agent2 executes even number of files
    For detalied slicing info: https://learn.microsoft.com/en-us/vsts/pipelines/test/parallel-testing-any-test-runner
    We use JUnit style test results to publish the test reports.
#>

$tests = Get-ChildItem .\ -Filter "test*" # search for test files with specific pattern.
$totalAgents = [int]$Env:SYSTEM_TOTALJOBSINPHASE # standard VSTS variables available using parallel execution; total number of parallel jobs running
$agentNumber = [int]$Env:SYSTEM_JOBPOSITIONINPHASE  # current job position
$testCount = $tests.Count

# below conditions are used if parallel pipeline is not used. i.e. pipeline is running with single agent (no parallel configuration)
if ($totalAgents -eq 0) {
    $totalAgents = 1
}
if (!$agentNumber -or $agentNumber -eq 0) {
    $agentNumber = 1
}

Write-Host "Total agents: $totalAgents"
Write-Host "Agent number: $agentNumber"
Write-Host "Total tests: $testCount"

$testsToRun= @()

# slice test files to make sure each agent gets unique test file to execute
For ($i=$agentNumber; $i -le $testCount;) {
    $file = $tests[$i-1]
    $testsToRun = $testsToRun + $file
    Write-Host "Added $file"
    $i = $i + $totalAgents 
 }

# join all test files seperated by space. pytest runs multiple test files in following format pytest test1.py test2.py test3.py
$testFiles = $testsToRun -Join " "
Write-Host "Test files $testFiles"
# write these files into variable so that we can run them using pytest in subsequent task. 
Write-Host "##vso[task.setvariable variable=pytestfiles;]$testFiles" 

If you take a look at the pipeline, it is possible to see that pytests are passing alright. It is also creating code coverage report accordingly. I believe the problem lies in consolidating code coverage reports into a single one.

Azure Pipeline

Now if looking for the summary of last run, it is possible to notice that there is only one attachment per run. This is probably the last executed job attachment, most likely. In this case test_chrome.py-results.xml.

Runs Tests plans

  • 1
    Please put your code and other details directly in the question. Thanks! – 10 Rep Jul 08 '20 at 21:54
  • 1
    It appears that it only published the last artifact during the parallel testing due to they have the same build id. The last artifact overwrite the previous ones. But in your scenario ,actually they have the same code coverage in each test run. So the final code coverage should be the same even if they are added together. – Andy Li-MSFT Jul 09 '20 at 10:04
  • @AndyLi-MSFT, do you know of a way to overcome this problem? I want to, in the next step, upload coverage to codecov.io but the way it is doing, wrong coverage would be displayed. Just the coverage of the last executed test would be displayed. – Daniel Kaminski de Souza Jul 09 '20 at 18:49
  • 1
    I also tried this but couldn't figure it out. The code coverage artifact is published with the name `CodeCoverage Report_BuildID`.To publish all the code coverage artifacts we need to make the name of each code coverage artifact unique. But cannot find a way to achieve that... – Andy Li-MSFT Jul 10 '20 at 07:29

1 Answers1

0

If I don't miss anything you need to call coverage combine somewhere in your pipeline (at the moment you don't) and then upload the combined coverage.

❯ coverage --help
Coverage.py, version 6.4 with C extension
Measure, collect, and report on code coverage in Python programs.

usage: coverage <command> [options] [args]

Commands:
    annotate    Annotate source files with execution information.
    combine     Combine a number of data files.
...

With regards to the powershell script to distribute pytests in different workers you could directly instruct pytest to do that for you with pytest_collection_modifyitems in conftest.py, or you could also install pytest-azure-devops

Cesc
  • 904
  • 1
  • 9
  • 17