diff --git a/.github/workflows/Calculator_Scenario13.yml b/.github/workflows/Calculator_Scenario13.yml new file mode 100644 index 0000000..512f508 --- /dev/null +++ b/.github/workflows/Calculator_Scenario13.yml @@ -0,0 +1,46 @@ +# This workflow will build a .NET project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net + +name: "Calculator Scenario 13" + +on: + push: + branches: [ "main" ] + paths: [ 'samples/Calculator/tests/**', 'samples/Calculator/src/**', '.github/workflows/Calculator_Scenario13.yml' ] + +jobs: + build: + + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./samples/Calculator/tests/Calculator.Server.Tests + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 7.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --collect "Code Coverage" --no-build --verbosity normal + - name: Install dotnet-coverage + run: dotnet tool install -g dotnet-coverage + - name: Convert .coverage report to cobertura + run: dotnet-coverage merge -r $GITHUB_WORKSPACE/samples/Calculator/tests/Calculator.Server.Tests/TestResults/*.coverage -f cobertura -o $GITHUB_WORKSPACE/report.cobertura.xml + - name: ReportGenerator + uses: danielpalme/ReportGenerator-GitHub-Action@5.1.24 + with: + reports: '${{ github.workspace }}/report.cobertura.xml' + targetdir: '${{ github.workspace }}/coveragereport' + reporttypes: 'MarkdownSummaryGithub' + - name: Upload coverage into summary + run: cat $GITHUB_WORKSPACE/coveragereport/SummaryGithub.md >> $GITHUB_STEP_SUMMARY + - name: Archive code coverage results + uses: actions/upload-artifact@v3 + with: + name: code-coverage-report + path: ./**/TestResults/**/*.coverage diff --git a/.github/workflows/Calculator_Scenario14.yml b/.github/workflows/Calculator_Scenario14.yml new file mode 100644 index 0000000..8e8ceaf --- /dev/null +++ b/.github/workflows/Calculator_Scenario14.yml @@ -0,0 +1,53 @@ +# This workflow will build a .NET project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net + +name: "Calculator Scenario 14" + +on: + push: + branches: [ "main" ] + paths: [ 'samples/Calculator/tests/**', 'samples/Calculator/src/**', '.github/workflows/Calculator_Scenario14.yml' ] + +jobs: + build: + + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./samples/Calculator + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 7.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Install dotnet-coverage + run: dotnet tool install -g dotnet-coverage + - name: Start server + run: dotnet-coverage collect --output report.coverage --session-id TagScenario14 "dotnet run --no-build" & + working-directory: ./samples/Calculator/src/Calculator.Server + - name: Run tests + run: dotnet test --collect "Code Coverage" --no-build --verbosity normal + working-directory: ./samples/Calculator/tests/Calculator.Server.IntegrationTests + - name: Stop server + run: dotnet-coverage shutdown TagScenario14 + - name: Merge coverage reports + run: dotnet-coverage merge -r -f cobertura -o $GITHUB_WORKSPACE/report.cobertura.xml *.coverage ../../src/Calculator.Server/report.coverage + working-directory: ./samples/Calculator/tests/Calculator.Server.IntegrationTests + - name: ReportGenerator + uses: danielpalme/ReportGenerator-GitHub-Action@5.1.24 + with: + reports: '${{ github.workspace }}/report.cobertura.xml' + targetdir: '${{ github.workspace }}/coveragereport' + reporttypes: 'MarkdownSummaryGithub' + - name: Upload coverage into summary + run: cat $GITHUB_WORKSPACE/coveragereport/SummaryGithub.md >> $GITHUB_STEP_SUMMARY + - name: Archive code coverage results + uses: actions/upload-artifact@v3 + with: + name: code-coverage-report + path: '${{ github.workspace }}/report.cobertura.xml' diff --git a/.github/workflows/Calculator_Scenario15.yml b/.github/workflows/Calculator_Scenario15.yml new file mode 100644 index 0000000..5d73587 --- /dev/null +++ b/.github/workflows/Calculator_Scenario15.yml @@ -0,0 +1,53 @@ +# This workflow will build a .NET project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net + +name: "Calculator Scenario 15" + +on: + push: + branches: [ "main" ] + paths: [ 'samples/Calculator/tests/**', 'samples/Calculator/src/**', '.github/workflows/Calculator_Scenario15.yml' ] + +jobs: + build: + + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./samples/Calculator + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 7.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Install dotnet-coverage + run: dotnet tool install -g dotnet-coverage + - name: Start code coverage collection + run: dotnet-coverage collect --output-format cobertura --output $GITHUB_WORKSPACE/report.cobertura.xml --session-id TagScenario15 --background --server-mode + working-directory: ./samples/Calculator/src/Calculator.Server + - name: Start server + run: dotnet-coverage connect --background TagScenario15 "dotnet run --no-build" + working-directory: ./samples/Calculator/src/Calculator.Server + - name: Run tests + run: dotnet-coverage connect TagScenario15 "dotnet test --no-build" + working-directory: ./samples/Calculator/tests/Calculator.Server.IntegrationTests + - name: Stop server + run: dotnet-coverage shutdown TagScenario15 + - name: ReportGenerator + uses: danielpalme/ReportGenerator-GitHub-Action@5.1.24 + with: + reports: '${{ github.workspace }}/report.cobertura.xml' + targetdir: '${{ github.workspace }}/coveragereport' + reporttypes: 'MarkdownSummaryGithub' + - name: Upload coverage into summary + run: cat $GITHUB_WORKSPACE/coveragereport/SummaryGithub.md >> $GITHUB_STEP_SUMMARY + - name: Archive code coverage results + uses: actions/upload-artifact@v3 + with: + name: code-coverage-report + path: '${{ github.workspace }}/report.cobertura.xml' diff --git a/samples/Calculator/README.md b/samples/Calculator/README.md index 3c09d8c..2bd4d83 100644 --- a/samples/Calculator/README.md +++ b/samples/Calculator/README.md @@ -22,4 +22,5 @@ Solution contains seven projects: 9. [***Scenario 09*** Code coverage for console application - static instrumentation](scenarios/scenario09/README.md) 10. [***Scenario 10*** Code coverage for console application - static instrumentation with instrument command](scenarios/scenario10/README.md) 11. [***Scenario 11*** Code coverage for child processes enabled](scenarios/scenario11/README.md) -12. [***Scenario 12*** Code coverage for child processes disabled](scenarios/scenario12/README.md) \ No newline at end of file +12. [***Scenario 12*** Code coverage for child processes disabled](scenarios/scenario12/README.md) +13. [***Scenario 13*** Code coverage for ASP.NET Core tests](scenarios/scenario13/README.md) \ No newline at end of file diff --git a/samples/Calculator/scenarios/scenario13/README.md b/samples/Calculator/scenarios/scenario13/README.md new file mode 100644 index 0000000..99a1bd3 --- /dev/null +++ b/samples/Calculator/scenarios/scenario13/README.md @@ -0,0 +1,90 @@ +# Scenario Description + +Collect code coverage for ASP.NET Core tests. Default format is binary (`.coverage` extension) which can be opened in Visual Studio Enterprise. + +# Collect code coverage using command line + +```shell +git clone https://github.com/microsoft/codecoverage.git +cd codecoverage/samples/Calculator/tests/Calculator.Server.Tests/ +dotnet test --collect "Code Coverage" +``` + +You can also use [run.ps1](run.ps1) to collect code coverage. + +# Collect code coverage inside github workflow + +To generate summary report `.coverage` report needs to be converted to `cobertura` report using `dotnet-coverage` tool. Then `reportgenerator` can be used to generate final github summary markdown. + +```yml + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 7.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --collect "Code Coverage" --no-build --verbosity normal + - name: Install dotnet-coverage + run: dotnet tool install -g dotnet-coverage + - name: Convert .coverage report to cobertura + run: dotnet-coverage merge -r $GITHUB_WORKSPACE/samples/Calculator/tests/Calculator.Server.Tests/TestResults/*.coverage -f cobertura -o $GITHUB_WORKSPACE/report.cobertura.xml + - name: ReportGenerator + uses: danielpalme/ReportGenerator-GitHub-Action@5.1.24 + with: + reports: '${{ github.workspace }}/report.cobertura.xml' + targetdir: '${{ github.workspace }}/coveragereport' + reporttypes: 'MarkdownSummaryGithub' + - name: Upload coverage into summary + run: cat $GITHUB_WORKSPACE/coveragereport/SummaryGithub.md >> $GITHUB_STEP_SUMMARY + - name: Archive code coverage results + uses: actions/upload-artifact@v3 + with: + name: code-coverage-report + path: ./**/TestResults/**/*.coverage +``` + +[Full source example](../../../../.github/workflows/Calculator_Scenario13.yml) + +[Run example](../../../../../../actions/workflows/Calculator_Scenario13.yml) + +# Collect code coverage inside Azure DevOps Pipelines + +```yml +steps: +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet restore' + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--no-restore --configuration $(buildConfiguration)' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet build' + +- task: DotNetCoreCLI@2 + inputs: + command: 'test' + arguments: '--no-build --configuration $(buildConfiguration) --collect "Code Coverage"' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet test' +``` + +> **_NOTE:_** Azure DevOps pipelines automatically recognize binary coverage report format. Code coverage results are automatically processed and published to Azure DevOps. No additional steps needed. + +[Full source example](azure-pipelines.yml) + +![alt text](azure-pipelines.jpg "Code Coverage tab in Azure DevOps pipelines") + +# Report example + +![alt text](example.report.jpg "Example report") + +[Link](example.report.coverage) \ No newline at end of file diff --git a/samples/Calculator/scenarios/scenario13/azure-pipelines.jpg b/samples/Calculator/scenarios/scenario13/azure-pipelines.jpg new file mode 100644 index 0000000..d8b7a46 Binary files /dev/null and b/samples/Calculator/scenarios/scenario13/azure-pipelines.jpg differ diff --git a/samples/Calculator/scenarios/scenario13/azure-pipelines.yml b/samples/Calculator/scenarios/scenario13/azure-pipelines.yml new file mode 100644 index 0000000..b5c22e3 --- /dev/null +++ b/samples/Calculator/scenarios/scenario13/azure-pipelines.yml @@ -0,0 +1,29 @@ +name: "Calculator Scenario 13" + +pool: + vmImage: 'ubuntu-latest' + +variables: + buildConfiguration: 'Debug' + projectPath: './samples/Calculator/tests/Calculator.Server.Tests/Calculator.Server.Tests.csproj' # this is specific to example - in most cases not needed + +steps: +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet restore' + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--no-restore --configuration $(buildConfiguration)' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet build' + +- task: DotNetCoreCLI@2 + inputs: + command: 'test' + arguments: '--no-build --configuration $(buildConfiguration) --collect "Code Coverage"' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet test' \ No newline at end of file diff --git a/samples/Calculator/scenarios/scenario13/example.report.coverage b/samples/Calculator/scenarios/scenario13/example.report.coverage new file mode 100644 index 0000000..2c746e2 Binary files /dev/null and b/samples/Calculator/scenarios/scenario13/example.report.coverage differ diff --git a/samples/Calculator/scenarios/scenario13/example.report.jpg b/samples/Calculator/scenarios/scenario13/example.report.jpg new file mode 100644 index 0000000..2c2b94e Binary files /dev/null and b/samples/Calculator/scenarios/scenario13/example.report.jpg differ diff --git a/samples/Calculator/scenarios/scenario13/run.ps1 b/samples/Calculator/scenarios/scenario13/run.ps1 new file mode 100644 index 0000000..d83e61a --- /dev/null +++ b/samples/Calculator/scenarios/scenario13/run.ps1 @@ -0,0 +1,2 @@ +cd $PSScriptRoot/../../tests/Calculator.Server.Tests +dotnet test --collect "Code Coverage" \ No newline at end of file diff --git a/samples/Calculator/scenarios/scenario14/README.md b/samples/Calculator/scenarios/scenario14/README.md new file mode 100644 index 0000000..b5e2e88 --- /dev/null +++ b/samples/Calculator/scenarios/scenario14/README.md @@ -0,0 +1,154 @@ +# Scenario Description + +Collect code coverage for ASP.NET Core integration tests. You can find here example how to collect coverage for server and tests if they are running in separate processes and server is started before tests execution. `dotnet-coverage` tool is used to collect code coverage for server. At the end code coverage results for server and tests are merged. Default format is binary (`.coverage` extension) which can be opened in Visual Studio Enterprise. In pipelines during merging final coverage report is converted into cobertura format and published. + +# Collect code coverage using command line + +```shell +git clone https://github.com/microsoft/codecoverage.git +cd codecoverage/samples/Calculator +dotnet build +dotnet tool install -g dotnet-coverage +cd src/Calculator.Server +dotnet-coverage collect --output report.coverage --session-id TagScenario14 "dotnet run --no-build" & +cd ../../tests/Calculator.Server.IntegrationTests +dotnet test --collect "Code Coverage" +dotnet-coverage shutdown TagScenario14 +dotnet-coverage merge -r --output merged.coverage *.coverage ../../src/Calculator.Server/report.coverage +``` + +You can also use [run.ps1](run.ps1) to collect code coverage. + +# Collect code coverage inside github workflow + +To generate summary report `.coverage` report needs to be converted to `cobertura` report using `dotnet-coverage` tool. Then `reportgenerator` can be used to generate final github summary markdown. + +```yml + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 7.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Install dotnet-coverage + run: dotnet tool install -g dotnet-coverage + - name: Start server + run: dotnet-coverage collect --output report.coverage --session-id TagScenario14 "dotnet run --no-build" & + working-directory: ./samples/Calculator/src/Calculator.Server + - name: Run tests + run: dotnet test --collect "Code Coverage" --no-build --verbosity normal + working-directory: ./samples/Calculator/tests/Calculator.Server.IntegrationTests + - name: Stop server + run: dotnet-coverage shutdown TagScenario14 + - name: Merge coverage reports + run: dotnet-coverage merge -r -f cobertura -o $GITHUB_WORKSPACE/report.cobertura.xml *.coverage ../../src/Calculator.Server/report.coverage + working-directory: ./samples/Calculator/tests/Calculator.Server.IntegrationTests + - name: ReportGenerator + uses: danielpalme/ReportGenerator-GitHub-Action@5.1.24 + with: + reports: '${{ github.workspace }}/report.cobertura.xml' + targetdir: '${{ github.workspace }}/coveragereport' + reporttypes: 'MarkdownSummaryGithub' + - name: Upload coverage into summary + run: cat $GITHUB_WORKSPACE/coveragereport/SummaryGithub.md >> $GITHUB_STEP_SUMMARY + - name: Archive code coverage results + uses: actions/upload-artifact@v3 + with: + name: code-coverage-report + path: '${{ github.workspace }}/report.cobertura.xml' +``` + +[Full source example](../../../../.github/workflows/Calculator_Scenario14.yml) + +[Run example](../../../../../../actions/workflows/Calculator_Scenario14.yml) + +# Collect code coverage inside Azure DevOps Pipelines + +```yml +steps: +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet restore' + +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + projects: '$(testProjectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet restore (tests)' + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--no-restore --configuration $(buildConfiguration)' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet build' + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--no-restore --configuration $(buildConfiguration)' + projects: '$(testProjectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet build (tests)' + +- task: DotNetCoreCLI@2 + inputs: + command: 'custom' + custom: "tool" + arguments: 'install -g dotnet-coverage' + displayName: 'install dotnet-coverage' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage collect --output $(Agent.TempDirectory)/server.coverage --session-id TagScenario14 "dotnet run --project $(projectPath) --no-build" &' + displayName: 'start server under coverage' + +- task: DotNetCoreCLI@2 + inputs: + command: 'test' + arguments: '--no-build --configuration $(buildConfiguration) --collect "Code Coverage;CoverageFileName=tests.coverage" --logger trx --results-directory $(Agent.TempDirectory)' + publishTestResults: false + projects: '$(testProjectPath)' # this is specific to example - in most cases not needed + displayName: 'execute integration tests' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage shutdown TagScenario14' + displayName: 'stop server' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage merge -f cobertura -o merged.cobertura.xml --recursive "*.coverage"' + workingDirectory: "$(Agent.TempDirectory)" + displayName: 'merge coverage results' + +- task: PublishTestResults@2 + inputs: + testResultsFormat: 'VSTest' + testResultsFiles: '$(Agent.TempDirectory)/**/*.trx' + publishRunAttachments: false + +- task: PublishCodeCoverageResults@2 + inputs: + summaryFileLocation: $(Agent.TempDirectory)/merged.cobertura.xml +``` + +> **_NOTE:_** To make sure that Code Coverage tab will be visible in Azure DevOps you need to make sure that previous steps will not publish test attachments (`publishRunAttachments: false` and `publishTestResults: false`). + +[Full source example](azure-pipelines.yml) + +![alt text](azure-pipelines.jpg "Code Coverage tab in Azure DevOps pipelines") + +# Report example + +![alt text](example.report.jpg "Example report") + +[Link](example.report.cobertura.xml) \ No newline at end of file diff --git a/samples/Calculator/scenarios/scenario14/azure-pipelines.jpg b/samples/Calculator/scenarios/scenario14/azure-pipelines.jpg new file mode 100644 index 0000000..1d758ce Binary files /dev/null and b/samples/Calculator/scenarios/scenario14/azure-pipelines.jpg differ diff --git a/samples/Calculator/scenarios/scenario14/azure-pipelines.yml b/samples/Calculator/scenarios/scenario14/azure-pipelines.yml new file mode 100644 index 0000000..27bcfe2 --- /dev/null +++ b/samples/Calculator/scenarios/scenario14/azure-pipelines.yml @@ -0,0 +1,80 @@ +name: "Calculator Scenario 14" + +pool: + vmImage: 'ubuntu-latest' + +variables: + buildConfiguration: 'Debug' + testProjectPath: './samples/Calculator/tests/Calculator.Server.IntegrationTests/Calculator.Server.IntegrationTests.csproj' # this is specific to example - in most cases not needed + projectPath: './samples/Calculator/src/Calculator.Server/Calculator.Server.csproj' # this is specific to example - in most cases not needed + +steps: +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet restore' + +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + projects: '$(testProjectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet restore (tests)' + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--no-restore --configuration $(buildConfiguration)' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet build' + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--no-restore --configuration $(buildConfiguration)' + projects: '$(testProjectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet build (tests)' + +- task: DotNetCoreCLI@2 + inputs: + command: 'custom' + custom: "tool" + arguments: 'install -g dotnet-coverage' + displayName: 'install dotnet-coverage' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage collect --output $(Agent.TempDirectory)/server.coverage --session-id TagScenario14 "dotnet run --project $(projectPath) --no-build" &' + displayName: 'start server under coverage' + +- task: DotNetCoreCLI@2 + inputs: + command: 'test' + arguments: '--no-build --configuration $(buildConfiguration) --collect "Code Coverage;CoverageFileName=tests.coverage" --logger trx --results-directory $(Agent.TempDirectory)' + publishTestResults: false + projects: '$(testProjectPath)' # this is specific to example - in most cases not needed + displayName: 'execute integration tests' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage shutdown TagScenario14' + displayName: 'stop server' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage merge -f cobertura -o merged.cobertura.xml --recursive "*.coverage"' + workingDirectory: "$(Agent.TempDirectory)" + displayName: 'merge coverage results' + +- task: PublishTestResults@2 + inputs: + testResultsFormat: 'VSTest' + testResultsFiles: '$(Agent.TempDirectory)/**/*.trx' + publishRunAttachments: false + +- task: PublishCodeCoverageResults@2 + inputs: + summaryFileLocation: $(Agent.TempDirectory)/merged.cobertura.xml \ No newline at end of file diff --git a/samples/Calculator/scenarios/scenario14/example.report.cobertura.xml b/samples/Calculator/scenarios/scenario14/example.report.cobertura.xml new file mode 100644 index 0000000..7934323 --- /dev/null +++ b/samples/Calculator/scenarios/scenario14/example.report.cobertura.xml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Calculator/scenarios/scenario14/example.report.jpg b/samples/Calculator/scenarios/scenario14/example.report.jpg new file mode 100644 index 0000000..5ebcba9 Binary files /dev/null and b/samples/Calculator/scenarios/scenario14/example.report.jpg differ diff --git a/samples/Calculator/scenarios/scenario14/run.ps1 b/samples/Calculator/scenarios/scenario14/run.ps1 new file mode 100644 index 0000000..4782555 --- /dev/null +++ b/samples/Calculator/scenarios/scenario14/run.ps1 @@ -0,0 +1,9 @@ +cd $PSScriptRoot/../.. +dotnet build +dotnet tool install -g dotnet-coverage +cd $PSScriptRoot/../../src/Calculator.Server +dotnet-coverage collect --output report.coverage --session-id TagScenario14 "dotnet run --no-build" & +cd $PSScriptRoot/../../tests/Calculator.Server.IntegrationTests +dotnet test --collect "Code Coverage" +dotnet-coverage shutdown TagScenario14 +dotnet-coverage merge -r --output merged.coverage *.coverage $PSScriptRoot/../../src/Calculator.Server/report.coverage \ No newline at end of file diff --git a/samples/Calculator/scenarios/scenario15/README.md b/samples/Calculator/scenarios/scenario15/README.md new file mode 100644 index 0000000..0d5eb69 --- /dev/null +++ b/samples/Calculator/scenarios/scenario15/README.md @@ -0,0 +1,151 @@ +# Scenario Description + +Collect code coverage for ASP.NET Core integration tests. You can find here example how to collect coverage for server and tests if they are running in separate processes and server is started before tests execution. `dotnet-coverage` tool in server mode is used to collect code coverage for server and tests. `connect` command is used to attach server and tests processes into coverage collection. + +# Collect code coverage using command line + +```shell +git clone https://github.com/microsoft/codecoverage.git +cd codecoverage/samples/Calculator +dotnet build +dotnet tool install -g dotnet-coverage +otnet-coverage collect --output-format cobertura --output report.cobertura.xml --session-id TagScenario15 --background --server-mode +cd src/Calculator.Server +dotnet-coverage connect --background TagScenario15 "dotnet run --no-build" +cd ../../tests/Calculator.Server.IntegrationTests +dotnet-coverage connect TagScenario15 "dotnet test --no-build" +dotnet-coverage shutdown TagScenario15 +``` + +You can also use [run.ps1](run.ps1) to collect code coverage. + +# Collect code coverage inside github workflow + +To generate summary report `.coverage` report needs to be converted to `cobertura` report using `dotnet-coverage` tool. Then `reportgenerator` can be used to generate final github summary markdown. + +```yml + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 7.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Install dotnet-coverage + run: dotnet tool install -g dotnet-coverage + - name: Start code coverage collection + run: dotnet-coverage collect --output-format cobertura --output $GITHUB_WORKSPACE/report.cobertura.xml --session-id TagScenario15 --background --server-mode + working-directory: ./samples/Calculator/src/Calculator.Server + - name: Start server + run: dotnet-coverage connect --background TagScenario15 "dotnet run --no-build" + working-directory: ./samples/Calculator/src/Calculator.Server + - name: Run tests + run: dotnet-coverage connect TagScenario15 "dotnet test --no-build" + working-directory: ./samples/Calculator/tests/Calculator.Server.IntegrationTests + - name: Stop server + run: dotnet-coverage shutdown TagScenario15 + - name: ReportGenerator + uses: danielpalme/ReportGenerator-GitHub-Action@5.1.24 + with: + reports: '${{ github.workspace }}/report.cobertura.xml' + targetdir: '${{ github.workspace }}/coveragereport' + reporttypes: 'MarkdownSummaryGithub' + - name: Upload coverage into summary + run: cat $GITHUB_WORKSPACE/coveragereport/SummaryGithub.md >> $GITHUB_STEP_SUMMARY + - name: Archive code coverage results + uses: actions/upload-artifact@v3 + with: + name: code-coverage-report + path: '${{ github.workspace }}/report.cobertura.xml' +``` + +[Full source example](../../../../.github/workflows/Calculator_Scenario15.yml) + +[Run example](../../../../../../actions/workflows/Calculator_Scenario15.yml) + +# Collect code coverage inside Azure DevOps Pipelines + +```yml +steps: +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet restore' + +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + projects: '$(testProjectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet restore (tests)' + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--no-restore --configuration $(buildConfiguration)' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet build' + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--no-restore --configuration $(buildConfiguration)' + projects: '$(testProjectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet build (tests)' + +- task: DotNetCoreCLI@2 + inputs: + command: 'custom' + custom: "tool" + arguments: 'install -g dotnet-coverage' + displayName: 'install dotnet-coverage' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage collect --output-format cobertura --output $(Agent.TempDirectory)/report.cobertura.xml --session-id TagScenario15 --background --server-mode' + displayName: 'start code coverage collection' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage connect --background TagScenario15 "dotnet run --no-build"' + workingDirectory: '$(Build.SourcesDirectory)/samples/Calculator/src/Calculator.Server/' + displayName: 'start server under coverage' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage connect TagScenario15 "dotnet test --configuration $(buildConfiguration) --no-build --logger trx --results-directory $(Agent.TempDirectory)"' + workingDirectory: '$(Build.SourcesDirectory)/samples/Calculator/tests/Calculator.Server.IntegrationTests/' + displayName: 'execute integration tests' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage shutdown TagScenario15' + displayName: 'stop code coverage collection' + +- task: PublishTestResults@2 + inputs: + testResultsFormat: 'VSTest' + testResultsFiles: '$(Agent.TempDirectory)/**/*.trx' + publishRunAttachments: false + +- task: PublishCodeCoverageResults@2 + inputs: + summaryFileLocation: $(Agent.TempDirectory)/report.cobertura.xml +``` + +[Full source example](azure-pipelines.yml) + +![alt text](azure-pipelines.jpg "Code Coverage tab in Azure DevOps pipelines") + +# Report example + +![alt text](example.report.jpg "Example report") + +[Link](example.report.cobertura.xml) \ No newline at end of file diff --git a/samples/Calculator/scenarios/scenario15/azure-pipelines.jpg b/samples/Calculator/scenarios/scenario15/azure-pipelines.jpg new file mode 100644 index 0000000..83e02a0 Binary files /dev/null and b/samples/Calculator/scenarios/scenario15/azure-pipelines.jpg differ diff --git a/samples/Calculator/scenarios/scenario15/azure-pipelines.yml b/samples/Calculator/scenarios/scenario15/azure-pipelines.yml new file mode 100644 index 0000000..9a84f42 --- /dev/null +++ b/samples/Calculator/scenarios/scenario15/azure-pipelines.yml @@ -0,0 +1,79 @@ +name: "Calculator Scenario 15" + +pool: + vmImage: 'ubuntu-latest' + +variables: + buildConfiguration: 'Debug' + testProjectPath: './samples/Calculator/tests/Calculator.Server.IntegrationTests/Calculator.Server.IntegrationTests.csproj' # this is specific to example - in most cases not needed + projectPath: './samples/Calculator/src/Calculator.Server/Calculator.Server.csproj' # this is specific to example - in most cases not needed + +steps: +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet restore' + +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + projects: '$(testProjectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet restore (tests)' + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--no-restore --configuration $(buildConfiguration)' + projects: '$(projectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet build' + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--no-restore --configuration $(buildConfiguration)' + projects: '$(testProjectPath)' # this is specific to example - in most cases not needed + displayName: 'dotnet build (tests)' + +- task: DotNetCoreCLI@2 + inputs: + command: 'custom' + custom: "tool" + arguments: 'install -g dotnet-coverage' + displayName: 'install dotnet-coverage' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage collect --output-format cobertura --output $(Agent.TempDirectory)/report.cobertura.xml --session-id TagScenario15 --background --server-mode' + displayName: 'start code coverage collection' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage connect --background TagScenario15 "dotnet run --no-build"' + workingDirectory: '$(Build.SourcesDirectory)/samples/Calculator/src/Calculator.Server/' + displayName: 'start server under coverage' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage connect TagScenario15 "dotnet test --configuration $(buildConfiguration) --no-build --logger trx --results-directory $(Agent.TempDirectory)"' + workingDirectory: '$(Build.SourcesDirectory)/samples/Calculator/tests/Calculator.Server.IntegrationTests/' + displayName: 'execute integration tests' + +- task: Bash@3 + inputs: + targetType: 'inline' + script: 'dotnet-coverage shutdown TagScenario15' + displayName: 'stop code coverage collection' + +- task: PublishTestResults@2 + inputs: + testResultsFormat: 'VSTest' + testResultsFiles: '$(Agent.TempDirectory)/**/*.trx' + publishRunAttachments: false + +- task: PublishCodeCoverageResults@2 + inputs: + summaryFileLocation: $(Agent.TempDirectory)/report.cobertura.xml \ No newline at end of file diff --git a/samples/Calculator/scenarios/scenario15/example.report.cobertura.xml b/samples/Calculator/scenarios/scenario15/example.report.cobertura.xml new file mode 100644 index 0000000..5850d30 --- /dev/null +++ b/samples/Calculator/scenarios/scenario15/example.report.cobertura.xml @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Calculator/scenarios/scenario15/example.report.jpg b/samples/Calculator/scenarios/scenario15/example.report.jpg new file mode 100644 index 0000000..6d7c87d Binary files /dev/null and b/samples/Calculator/scenarios/scenario15/example.report.jpg differ diff --git a/samples/Calculator/scenarios/scenario15/run.ps1 b/samples/Calculator/scenarios/scenario15/run.ps1 new file mode 100644 index 0000000..46811d8 --- /dev/null +++ b/samples/Calculator/scenarios/scenario15/run.ps1 @@ -0,0 +1,10 @@ +cd $PSScriptRoot/../.. +dotnet build +dotnet tool install -g dotnet-coverage +dotnet-coverage collect --output-format cobertura --output report.cobertura.xml --session-id TagScenario15 --background --server-mode +cd $PSScriptRoot/../../src/Calculator.Server +dotnet-coverage connect --background TagScenario15 "dotnet run --no-build" +cd $PSScriptRoot/../../tests/Calculator.Server.IntegrationTests +dotnet-coverage connect TagScenario15 "dotnet test --no-build" +dotnet-coverage shutdown TagScenario15 +cd $PSScriptRoot/../.. \ No newline at end of file diff --git a/samples/Calculator/tests/Calculator.Server.IntegrationTests/IntegrationTests.cs b/samples/Calculator/tests/Calculator.Server.IntegrationTests/IntegrationTests.cs index 77c5a4a..652a471 100644 --- a/samples/Calculator/tests/Calculator.Server.IntegrationTests/IntegrationTests.cs +++ b/samples/Calculator/tests/Calculator.Server.IntegrationTests/IntegrationTests.cs @@ -1,4 +1,5 @@ using NUnit.Framework; +using System.Runtime.InteropServices; namespace Calculator.Server.IntegrationTests; @@ -9,9 +10,11 @@ public class IntegrationTests public IntegrationTests() { + int port = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 5291 : 5000; + _client = new HttpClient() { - BaseAddress = new Uri(" http://localhost:5291"), + BaseAddress = new Uri($"http://localhost:{port}"), }; }