MetricsAssertions.TUnit
0.3.0
Prefix Reserved
dotnet add package MetricsAssertions.TUnit --version 0.3.0
NuGet\Install-Package MetricsAssertions.TUnit -Version 0.3.0
<PackageReference Include="MetricsAssertions.TUnit" Version="0.3.0" />
<PackageVersion Include="MetricsAssertions.TUnit" Version="0.3.0" />
<PackageReference Include="MetricsAssertions.TUnit" />
paket add MetricsAssertions.TUnit --version 0.3.0
#r "nuget: MetricsAssertions.TUnit, 0.3.0"
#:package MetricsAssertions.TUnit@0.3.0
#addin nuget:?package=MetricsAssertions.TUnit&version=0.3.0
#tool nuget:?package=MetricsAssertions.TUnit&version=0.3.0
MetricsAssertions.TUnit
Scope: Test projects only. Not intended for production code.
TUnit-native fluent assertions over System.Diagnostics.Metrics instruments, built on the first-party MetricCollector testing primitive. AOT-compatible, trimmable, no runtime reflection in the assertion path.
What ships
Fluent Assert.That(...).Has* assertions over three receivers:
| Receiver | Assertions |
|---|---|
InstrumentCapture |
counter / up-down-counter totals, measurement count, emptiness, last value (exact or within tolerance), tag presence |
MeasurementSet |
totals, counts, histogram sum / average / range, exact, tolerant, and order-insensitive samples, tag-consistency |
MeterCapture |
per-instrument totals, counts, and tag presence by name |
The framework-agnostic core (MetricsAssertions) ships the InstrumentCapture / MeterCapture capture types, the queryable MeasurementSet, MeterInspector, and the CapturedMeasurement record (instrument name, value projected to double, tags, timestamp). The by-name captures (InstrumentCapture.OfName, MeterCapture.For) take an optional meter scope (v0.2.0+) so a meter created by an IMeterFactory (the ASP.NET Core DI metrics path) can be captured.
Install
dotnet add package MetricsAssertions.TUnit
Requirements: TUnit 1.54.0 or later, .NET 10. The framework-agnostic MetricsAssertions core comes transitively.
Quick start
using System.Diagnostics.Metrics;
using MetricsAssertions;
using var meter = new Meter("MyCompany.Orders");
var placed = meter.CreateCounter<long>("orders.placed");
using var capture = InstrumentCapture.Of(placed);
placed.Add(1);
placed.Add(1);
await Assert.That(capture).HasMeasurementCount(2);
The full reference is in the GitHub README.
License
MIT.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- MetricsAssertions (>= 0.3.0)
- Microsoft.Extensions.Diagnostics.Testing (>= 10.7.0)
- TUnit.Assertions (>= 1.54.0)
- TUnit.Core (>= 1.54.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
View the rendered release notes: https://github.com/JohnVerheij/MetricsAssertions.TUnit/releases/tag/v0.3.0
Minor release. Adds absolute-tolerance overloads to the value assertions, closing the asymmetry where the histogram aggregates (`HasSampleSum` / `HasSampleAverage`) accepted a tolerance but the value assertions compared doubles exactly. Purely additive; the `0.2.0` ApiCompat baseline is preserved.
### Added
- **`HasLastValue(double expected, double tolerance)`** on an `InstrumentCapture` asserts the most recent value within an absolute tolerance, the tolerant counterpart of `HasLastValue(double)` for gauges fed computed doubles (where `0.1 + 0.2 != 0.3` exact comparison flakes).
- **`HasSamples(IReadOnlyList<double> expected, double tolerance)`** and **`HasSamplesInAnyOrder(IReadOnlyList<double> expected, double tolerance)`** on a `MeasurementSet` assert the samples within an absolute per-sample tolerance, in order and order-independent respectively. The framework-agnostic core gains the matching `MeasurementSet.SamplesEqual(expected, tolerance)` / `SamplesEquivalentTo(expected, tolerance)` comparison primitives. Every tolerance overload rejects a non-finite or negative tolerance with `ArgumentOutOfRangeException`, so an invalid tolerance fails fast instead of silently matching everything (`NaN`) or nothing (negative).
### Documentation
- **`MeasurementSet.Total`** now documents that the sum is rounded to a `long` with banker's rounding (round half to even), so a `Counter<double>` with a fractional total is evaluated as an integer. For an exact fractional total, compare `Sum` directly or use `HasSampleSum(expected, tolerance)`.