Benchmarking .NET test frameworks: xUnit v3, NUnit, MSTest, and TUnit

 
 
  • Gérald Barré
Choosing a test framework in .NET used to be a question of taste. xUnit, NUnit, and MSTest all discovered tests by reflection, all ran on VSTest, and the differences that mattered were the attribute names and the assertion style. Performance was not part of the conversation because there was nothing much to compare. Two things changed that. Every framework now ships a Microsoft.Testing.Platform runner,… [read more]

Run temporary containers in .NET tests with Meziantou.Framework.TemporaryContainers

 
 
  • Gérald Barré
Integration tests are much more valuable when they run against real services. Instead of mocking a database or cache, you can start a temporary container, run your test, and dispose everything at the end. The Meziantou.Framework.TemporaryContainers package provides a lightweight API to manage disposable containers from .NET. Its main difference with the existing libraries is that it is not tied to Docker.… [read more]

Generate and review the public API of a .NET library

 
 
  • Gérald Barré
When maintaining a library, one of the easiest ways to introduce a breaking change is to update a public type without noticing its impact on consumers. You can use the Microsoft.CodeAnalysis.PublicApiAnalyzers analyzer to generate a file with the list of members. However, I don't like it as the members are not in C# syntax. Also, if you don't have the same public API for all target frameworks, you get… [read more]

Limit what NuGet packages can do in your project

 
 
  • Gérald Barré
When you add a NuGet package to a project, you often think about the runtime library only. In reality, packages can also import MSBuild props/targets and Roslyn analyzers. Those assets run during restore, design-time build, or build. I've already provided some examples of how this can cause issues in . This means a package can execute code on your machine or in CI without you notice. If you only need a… [read more]

Reproducible Builds and Snapshot Testing: Handling File Paths in .NET

 
 
  • Gérald Barré
Reproducible builds in .NET replace file paths with placeholder values to enable reproducible builds and prevent leaking local development paths in binary outputs. This is a common practice on CI/CD pipelines. However, libraries that rely on actual file paths to function, like snapshot testing frameworks, face a challenge: they need to know where to store and load snapshot files on disk. This post… [read more]

Snapshot testing in .NET with Meziantou.Framework.SnapshotTesting

 
 
  • Gérald Barré
Snapshot testing is a technique where the output of a function or component is serialized and saved to disk the first time the test runs. On every subsequent run, the library re-serializes the output and compares it against the saved file. If they differ, the test fails. Meziantou.Framework.SnapshotTesting is a .NET library that makes snapshot testing straightforward. It handles serialization, file… [read more]

Safely passing extra arguments in GitHub Actions workflows using PowerShell

 
 
  • Gérald Barré
When creating reusable GitHub Actions workflows or composite actions, you often need to allow callers to provide extra arguments to a command. For example, a workflow that builds a .NET project might accept additional arguments for dotnet build. Handling these arguments safely requires careful attention to prevent script injection and ensure proper argument splitting. The problem with direct interpolation… [read more]

Enable SHA Pinning for GitHub Actions Across Personal Repositories

 
 
  • Gérald Barré
Pinning GitHub Actions to a full-length commit SHA is one of the simplest ways to reduce supply chain risk in your workflows. It ensures that a workflow keeps using the exact code you reviewed, instead of silently following a moving tag or branch. Tags are convenient, but they are mutable. A workflow that uses actions/checkout@v4 or a third-party action pinned to a tag can start running different code… [read more]