OmniAssert 1.1.2
dotnet add package OmniAssert --version 1.1.2
NuGet\Install-Package OmniAssert -Version 1.1.2
<PackageReference Include="OmniAssert" Version="1.1.2" />
<PackageVersion Include="OmniAssert" Version="1.1.2" />
<PackageReference Include="OmniAssert" />
paket add OmniAssert --version 1.1.2
#r "nuget: OmniAssert, 1.1.2"
#:package OmniAssert@1.1.2
#addin nuget:?package=OmniAssert&version=1.1.2
#tool nuget:?package=OmniAssert&version=1.1.2
<div align="center"> <img src="https://raw.githubusercontent.com/bolorundurowb/OmniAssert/refs/heads/master/assets/omni-assert-logo.svg" alt="omni assert logo" /> <h1 align="center">Omni Assert</h1> </div>
<p align="center"> <a href="https://github.com/bolorundurowb/OmniAssert/actions/workflows/build-and-test.yml"> <img src="https://github.com/bolorundurowb/OmniAssert/actions/workflows/build-and-test.yml/badge.svg" alt="Build, Test & Coverage" /> </a> <a href="https://codecov.io/gh/bolorundurowb/OmniAssert"> <img src="https://codecov.io/gh/bolorundurowb/OmniAssert/graph/badge.svg?token=J9ssbN9xYA" alt="codecov" /> </a> <a href="./LICENSE"> <img src="https://img.shields.io/badge/license-GPLv3-orange.svg" alt="License" /> </a> </p>
Provenance: OmniAssert was built with substantial help from AI-assisted coding tools. If you are evaluating it for production, security-sensitive, or compliance-heavy use, apply the same scrutiny you would to any rapidly authored codebase: read critical paths, run your own tests, and satisfy your organisation’s review and supply-chain policies.
Introduction
OmniAssert is a modern, fluent assertion library for .NET that makes your test code more readable and your test failures more informative. Built for .NET 10 and C# 14, it combines the best ideas from established assertion frameworks while adding powerful compile-time features that help you write better tests faster.
At its core, OmniAssert provides an expressive, natural-language API for assertions: Verify(user.Email).ToContain("@")
reads like plain English. When assertions fail, you get rich, detailed error messages that include the actual and
expected values, the expression that failed, and contextual information about what went wrong—making debugging faster
and less frustrating.
What sets OmniAssert apart
Deep object comparison: The
ToBeEquivalentToassertion performs intelligent structural comparison of complex object graphs, recursively comparing public properties, handling collections as unordered multisets, and safely navigating circular references. When objects don't match, you get a clear, hierarchical diff showing exactly where they diverge.Soft assertions with AssertionScope: Wrap multiple assertions in an
AssertionScopeto collect all failures in a test before reporting them together. No more fixing one assertion at a time—see everything that's wrong in one test run.Compile-time assertion enhancement (optional): Enable Roslyn interceptors to get richer diagnostics for boolean expressions. When
VerifyExpression(x > 0 && count < limit)fails, you see not just "condition was false" but the actual values ofx,count, andlimit. An advanced rewrite mode can even capture intermediate sub-expression values for complex logical conditions.Comprehensive API coverage: From basic equality and comparison checks to collection assertions, exception testing (sync and async), type checks, string pattern matching, date/time comparisons, nullable handling, and more—all with consistent, fluent syntax.
Exceptional diagnostics: Leveraging
[CallerArgumentExpression]and optional source generators, OmniAssert captures the text of your assertion expressions automatically, so failure messages show you exactly what you tested, not just that something failed.Rich value formatting: When assertions fail, OmniAssert provides clear, highlighted output using ANSI colours. Complex types like collections are automatically formatted to show their contents (up to 10 items) rather than just the type name, making it easier to see exactly what caused the mismatch.
Whether you're writing unit tests, integration tests, or behaviour-driven scenarios, OmniAssert helps you express intent clearly and diagnose failures quickly.
Requirements
- Runtime: projects targeting .NET 10 (or a compatible TFM) can reference the
OmniAssertNuGet package. The runtime assembly name isOmniAssert.Core. - Optional interceptors: .NET 10 SDK, C# 14, and the MSBuild properties in Optional: richer boolean failures with interceptors. Interceptors only affect
VerifyExpression(bool, string?)(thestringis normally supplied by[CallerArgumentExpression]).
Install
Add the package to your test project:
<ItemGroup>
<PackageReference Include="OmniAssert" Version="1.1.2" />
</ItemGroup>
If you are building from this repository or a fork (project references instead of NuGet), see CONTRIBUTING.md for layout, build commands, and how to wire the analyzer like the sample project.
Quick start
- Reference
OmniAssert(see Install). - Write
.Verify(…)on any value or expression. - For booleans, you can also use
.VerifyExpression().
using OmniAssert;
[Fact]
public void Should_validate_user()
{
user.Id.Verify().ToBeGreaterThan(0);
user.Email.Verify().ToContain("@");
user.IsActive.Verify().ToBeTrue();
}
Assertion Types
OmniAssert provides a rich set of extension methods for various types. All assertions begin with .Verify() or specialized methods like .VerifyNullable().
Basic Values & Numeric
Assertions for all standard numeric types (including BigInteger).
answer.Verify().ToBe(42);
count.Verify().ToBeGreaterThan(0);
price.Verify().ToBeApproximately(9.99, 0.01);
score.Verify().ToBeOneOf(10, 20, 30);
ToBe(expected)/NotToBe(unexpected)ToBeGreaterThan(threshold)/ToBeGreaterThanOrEqualTo(threshold)ToBeLessThan(threshold)/ToBeLessThanOrEqualTo(threshold)ToBeInRange(min, max)ToBeApproximately(expected, precision)ToBeOneOf(values...)
Strings
Fluent assertions for text analysis.
name.Verify().ToStartWith("John");
email.Verify().ToMatch(@"^[^@\s]+@[^@\s]+\.[^@\s]+$");
bio.Verify().ToHaveLengthGreaterThan(10);
role.Verify().ToBeIgnoringCase("admin");
ToContain(substring)/NotToContain(substring)ToStartWith(prefix)/ToEndWith(suffix)ToMatch(regex)ToBeIgnoringCase(expected)/ToBeOneOf(values...)ToBeNull()/NotToBeNull()ToBeEmpty()/NotToBeEmpty()ToBeNullOrEmpty()/ToBeNullOrWhiteSpace()/NotToBeNullOrWhiteSpace()ToHaveLength(expected)/ToHaveLengthGreaterThan(n)/ToHaveLengthLessThan(n)
Collections & Dictionaries
Deep verification for sequences and key-value pairs.
users.Verify().ToHaveCount(3);
items.Verify().ToContain(targetItem);
results.Verify().ToBeUnique();
settings.Verify().ContainKey("Theme");
ToHaveCount(n)ToHaveCountGreaterThan(n)/ToHaveCountLessThan(n)ToHaveCountMatching(n, predicate)ToBeEmpty()/NotToBeEmpty()ToContain(item)/NotToContain(item)ToContain(predicate)/AllSatisfy(predicate)/AnySatisfy(predicate)/NoneSatisfy(predicate)ToBeUnique()/ToHaveUniqueCount(n)ToBeInAscendingOrder()/ToBeInDescendingOrder()ToBeEquivalentTo(other)(Multiset equivalence—same elements, order ignored)ToBeNull()/NotToBeNull()ToHaveCount(n)ContainKey(key)/NotContainKey(key)/ContainValue(value)/NotContainValue(value)/HaveValue(key, value)
Objects & Equivalence
Verify object identity, types, and structural equality.
instance.Verify().ToBeOfType<MyClass>();
actualDto.Verify().ToBeEquivalentTo(expectedDto);
ToBe(expected)(Reference equality)ToBeNull()/NotToBeNull()ToBeOfType<T>()/NotToBeOfType<T>()ToBeAssignableTo<T>()/NotToBeAssignableTo<T>()ToBeEquivalentTo(expected)(Recursive property comparison with diff)
Exceptions & Tasks
Verify synchronous and asynchronous code behavior.
// Synchronous
Action act = () => service.DoWork();
act.Throws<InvalidOperationException>().WithMessage("Failed");
// Asynchronous
Func<Task> asyncAct = () => service.DoWorkAsync();
await asyncAct.ThrowsAsync<ArgumentException>();
// Timeouts
await TimeSpan.FromSeconds(2).CompleteWithin(() => longRunningTask);
Throws<T>()/ThrowsAsync<T>()NotThrow()/NotThrowAsync()WithMessage(expected)/WithMessageContaining(substring)WithInnerException<TInner>()CompleteWithin(action)
Dates, Times & Other Types
Assertions for temporal types, GUIDs, Enums, and URIs.
dateTime.Verify().ToBeAfter(yesterday);
timeSpan.Verify().ToBePositive();
guid.Verify().NotToBeEmpty();
uri.Verify().HaveHost("github.com");
DateTime/DateTimeOffset:ToBeBefore,ToBeAfter,ToBeWithinDateOnly/TimeOnly:ToBeBefore,ToBeAfterTimeSpan:ToBePositive,ToBeNegativeGuid:ToBeEmpty,NotToBeEmptyEnum:ToBe,ToBeOneOfUri:HaveScheme,HaveHost,HavePath,HaveQuery
File System
Verify files and directories exist and check their properties.
"config.json".FileExists().HaveContent(expectedJson);
"temp".DirectoryExists().BeEmpty();
FileExists()→HaveContent(text),BeEmpty()DirectoryExists()→BeEmpty()
Soft Assertions: AssertionScope
Use AssertionScope to collect multiple failures and report them all at once when the scope is disposed.
using (new AssertionScope())
{
user.Name.Verify().ToBe("John");
user.Age.Verify().ToBe(30);
user.Email.Verify().ToContain("@");
}
Booleans: Verify() vs VerifyExpression()
OmniAssert provides two ways to assert boolean conditions:
- Fluent style:
flag.Verify().ToBeTrue()- consistent with other assertions. - Expression style:
condition.VerifyExpression()- best for complex logical conditions.
// Fluent
isValid.Verify().ToBeTrue();
// Expression (with rich diagnostics via bundled interceptors)
(x > 0 && count < limit).VerifyExpression();
Compile-time boolean diagnostics (interceptors)
The bundled Roslyn generator is on by default. When active, it rewrites VerifyExpression() call sites at compile time to capture sub-expression values, so failure messages show the individual operands—not just "condition was false".
To opt out, add the following to your test project:
<PropertyGroup>
<OmniAssertDisableVerifyInterceptors>true</OmniAssertDisableVerifyInterceptors>
</PropertyGroup>
C# 14 / .NET 10 requirement: interceptors require
LangVersion≥ 14 and theInterceptorsNamespacesproperty. Both are met automatically when targeting .NET 10 with the default SDK settings, but if you pin an earlier language version you must add:<PropertyGroup> <LangVersion>14</LangVersion> <InterceptorsNamespaces>$(InterceptorsNamespaces);OmniAssert.Generated</InterceptorsNamespaces> </PropertyGroup>
When active:
flag.VerifyExpression()(bare identifier) becomesflag.Verify(expression).ToBeTrue().(complexExpr).VerifyExpression()captures all operands so failure messages show each value.
License
This project is licensed under the GNU General Public License v3.0. See LICENSE.
| 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
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.1.2 | 83 | 5/18/2026 |
| 1.1.1 | 97 | 5/17/2026 |
| 1.1.0 | 98 | 5/17/2026 |
| 1.0.1 | 90 | 5/17/2026 |
| 1.0.0 | 89 | 5/16/2026 |
| 1.0.0-beta.1 | 47 | 5/7/2026 |
| 1.0.0-beta.0 | 44 | 5/6/2026 |
| 1.0.0-alpha.1 | 42 | 5/5/2026 |
v1.1.2
- Added ToBeNull() and NotToBeNull() assertions to DictionaryAssertions.
- Added ToHaveCount(n) assertion to DictionaryAssertions.
v1.1.1
- Added NotContainValue to the Dictionary assertions
- Fix float numeric comparisons
v1.1.0
- Added ToBeNull() and NotToBeNull() assertions to ObjectAssertions.
- Added NotToBeOfType<T>() and NotToBeAssignableTo<T>() assertions to ObjectAssertions.
v1.0.1
- Added ToBe(expected) for identity/reference equality checks to Collection, Dictionary, Guid, Uri, and Object assertions.
- Enhanced null safety in CollectionAssertions and DictionaryAssertions to provide descriptive failures instead of NullReferenceException.
- Added WithMessageIgnoringCase to ExceptionAssertions for flexible message verification.
- Improved failure diagnostics with recursive collection content formatting (up to 10 items) in OmniAssertionException.
- Standardized ANSI color highlighting across all numeric, date, and time assertions for consistent terminal output.
- Unified VerifyExpression failure path with fluent assertions via VerificationFlow.Fail.
- Optimized source generator by removing unreachable code and reducing redundant parentheses in rewritten expressions.