Unit Tests and Code Coverage in GitHub Actions: A Developer’s Guide to Streamlining .NET Workflows
After successfully setting up unit tests and code coverage in Azure DevOps, I decided to replicate the process in GitHub Actions. This comparison would allow me to explore the differences between the two environments. Unlike Azure DevOps, GitHub Actions doesn’t have built-in, sleek graphical interfaces for reviewing outcomes, but it offers flexibility and integration capabilities. For now, I’ve set up a workflow that executes tests and provides code coverage results via the standard GitHub Actions interface. While it’s functional, there’s room for improvement, especially in presenting code coverage data in a more visually appealing way.
Here’s a breakdown of how I set up the workflow, its key components, and some thoughts on next steps.
Workflow Overview: Accelerating .NET Workloads
To streamline the development process for my .NET application workloads, I created a new GitHub Actions workflow named atat-pull-request-dotnet-unit-tests.yaml. This workflow is designed to run during the pull request process, ensuring that unit tests are executed and code coverage data is collected and uploaded.
To make the workflow dynamic and configurable, I defined a set of environment variables that control key settings like build configuration, working directory, solution file, and test category. These variables simplify the workflow and make it easier to point the .NET CLI at the correct projects.
Key Environment Variables
env:
BuildConfiguration: Release
WorkingDirectory: src/dotnet
SolutionFile: Foo.sln
TestCategory: Unit
- BuildConfiguration: Specifies the build mode (e.g., Release or Debug).
- WorkingDirectory: Points to the directory containing the source code.
- SolutionFile: The name of the solution file to build and test.
- TestCategory: Filters the tests to run (e.g., Unit tests).
Step-by-Step Setup
- Restoring Dependencies The first step in the workflow is to restore the solution’s dependencies using the .NET CLI. The dotnet restorecommand pulls in all necessary NuGet packages, ensuring the project is ready to build.
- name: Restore dependencies
working-directory: $
run: |
dotnet restore $
- Building the Solution
Next, the solution is built using the specified configuration (in this case, Release). This step ensures that the project compiles successfully before running tests.
- name: Build solution
working-directory: $
run: |
dotnet build $ --configuration $
- Running Tests with Code Coverage
In this step, the unit tests are executed with code coverage enabled. The –collect:”XPlat Code Coverage” flag generates coverage data in Cobertura format, which is a standard XML format for reporting code coverage.
- name: Run tests with code coverage
working-directory: $
run: |
dotnet test $ \
--configuration $ \
--filter "Category=$" \
--collect:"XPlat Code Coverage" \
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura
Unlike Azure DevOps, where tasks like DotNetCoreCLI@2 provide built-in actions for these steps, GitHub Actions relies on traditional shell scripting. This approach is more manual but still effective.
- Publishing Code Coverage Results
Once the tests are complete, the workflow uploads the Cobertura coverage report as an artifact. This allows you to download and review the report later.
- name: Publish code coverage results
uses: actions/upload-artifact@v3
with:
name: code-coverage-report
path: '**/coverage.cobertura.xml'
At this stage, the workflow produces a Cobertura XML file, but GitHub Actions doesn’t provide a built-in way to visualize this data. Exploring HTML output or integrating a third-party tool to render coverage reports might be the next logical step.
Challenges and Next Steps
While this workflow successfully sets up unit testing and code coverage in GitHub Actions, it’s clear that GitHub lacks the visual polish of Azure DevOps for reviewing test and coverage results. To address this, I plan to:
- Explore ways to generate and display HTML reports directly in GitHub Actions.
- Investigate third-party integrations or tools that provide graphical representations of coverage data.
- Iterate on this workflow to improve the overall developer experience.
If you have suggestions for handling Cobertura reports or know of tools that work well with GitHub Actions, I’d love to hear them!
Conclusion
Setting up unit tests and code coverage in GitHub Actions is a straightforward process, but it requires more manual scripting compared to Azure DevOps — which I personally prefer as it is more portable to other pipeline tools and platforms.
Despite the lack of built-in graphical interfaces, GitHub Actions offers the flexibility to customize workflows and integrate with external tools. For now, I’m satisfied with the current setup, but I see potential to enhance it further. With a bit more exploration and iteration, this workflow could become a powerful tool for accelerating .NET application workloads. Let me know your thoughts or share your tips for improving workflows like this!