SweetAssert 1.0.0
dotnet add package SweetAssert --version 1.0.0
NuGet\Install-Package SweetAssert -Version 1.0.0
<PackageReference Include="SweetAssert" Version="1.0.0" />
<PackageVersion Include="SweetAssert" Version="1.0.0" />
<PackageReference Include="SweetAssert" />
paket add SweetAssert --version 1.0.0
#r "nuget: SweetAssert, 1.0.0"
#:package SweetAssert@1.0.0
#addin nuget:?package=SweetAssert&version=1.0.0
#tool nuget:?package=SweetAssert&version=1.0.0
SweetAssert
Fluent, chainable assertions for xUnit v3, built on C# 14 extension members.
SweetAssert wraps Xunit.Assert in a small fluent surface so assertions read
left-to-right and chain:
using SweetAssert;
using Xunit;
Assert.That("Hello, world")
.StartsWith("Hello")
.Contains("world")
.DoesNotContain("goodbye");
Every call returns the same Asserter<T>, and each assertion delegates straight
to the matching Xunit.Assert method, so failures still throw the underlying
xUnit exception — you keep xUnit's messages, runners, and tooling.
Requirements
- .NET SDK 10 or later (C# 14 / extension members)
- xUnit v3 (
xunit.v3.assert)
The library targets netstandard2.0, so it can be consumed from any test
project on a modern toolchain.
Install
Not published as a package yet. Reference the project directly:
<ProjectReference Include="../SweetAssert/SweetAssert.csproj" />
Usage
Assert.That(...)
AssertThat adds a static That member to Xunit.Assert:
Assert.That(order.Total).InRange(10m, 100m);
Assert.That(name).Equal("Ada");
An optional IComparer<T> is remembered on the Asserter<T> and used as the
default for range checks:
Assert.That(version, SemVerComparer.Instance)
.InRange(lowerBound, upperBound);
Intrusive style
using SweetAssert.Intrusive; adds an .Assert property to every value:
using SweetAssert.Intrusive;
result.Assert.Equal(expected);
"café".Assert.Contains("f");
Import it only in the files where you want it.
Assert.ThatSequence(...)
Collections use a separate entry point so the element type is inferred and lambdas
work without annotation (Assert.That(collection) would bind to the collection's
concrete type, which the sequence assertions can't attach to):
Assert.ThatSequence(new[] { 1, 2, 3 })
.NotEmpty()
.Distinct()
.Contains(x => x > 2)
.DoesNotContain(0);
Assert.ThatSequence(orders)
.Single(o => o.IsPriority) // returns Asserter<Order>
.Equal(expectedPriorityOrder);
Single() / Single(predicate) return an Asserter<T> for the single element, so
you can keep chaining scalar assertions on it.
Assert.ThatAction(...)
Wraps a delegate so the throw assertions can invoke it and hand you the caught
exception as an Asserter<TException> to chain on:
var ex = Assert.ThatAction(() => Parse(input)).Throws<FormatException>();
Assert.ThatAction(() => account.Withdraw(-1))
.Throws<ArgumentOutOfRangeException>(e => e.ParamName == "amount");
await Assert.ThatAction(() => client.SendAsync(request))
.Throws<HttpRequestException>();
Overloads accept Action, Func<object?> (property getters), and Func<Task>;
the Func<Task> overload's assertions return Task<Asserter<TException>>, so
await the call. Throws<T> / ThrowsAny<T> take an optional
Func<TException, bool> predicate the caught exception must satisfy.
Type assertions
IsType / IsAssignableFrom hang off Assert.That(...) directly and narrow the
asserter to the checked type:
var result = Assert.That(response).IsType<OkObjectResult>(); // Asserter<OkObjectResult>
Assert.That(result.Value.StatusCode).Equal(200);
Assert.That(handler).IsAssignableFrom<IDisposable>();
Assert.That(value).IsNotType<string>();
IsNotType / IsNotAssignableFrom return the receiver (as IValueAsserter) so
you can stack further type checks; the narrowing ones flow into every other
assertion.
Equivalence
Equivalent compares by public structure (xUnit's Assert.Equivalent), so the
expected side can be a partial DTO or anonymous type:
Assert.That(response).Equivalent(new { Status = "ok", Items = 3 });
Assert.That(response).Equivalent(new { Status = "ok" }, strict: true); // fails: extra members
Assert.That(order).Equivalent(o => o.Total == expectedTotal); // predicate form
Assert.That(snapshot).NotEquivalent(previousSnapshot);
Assertions
| Applies to | Methods |
|---|---|
any T |
IsNull, IsNotNull; Equal, NotEqual (optional IEqualityComparer<T>); Same, NotSame (reference types); Equivalent / NotEquivalent (structural, optional strict), Equivalent(Func<T,bool>); IsType<T> / IsType<T>(exactMatch), IsAssignableFrom<T>, IsNotType<T>, IsNotAssignableFrom<T> |
bool / bool? |
IsTrue, IsFalse (optional user message) |
double / float / decimal / DateTime / DateTimeOffset |
Equal / NotEqual with a precision (decimal places, optional MidpointRounding), tolerance (double/float), or TimeSpan (dates) |
string |
Contains, DoesNotContain, StartsWith, EndsWith, Matches, DoesNotMatch |
IComparable |
InRange, NotInRange (optional IComparer<T>) |
IEnumerable<T> |
Contains, DoesNotContain (value or predicate), Empty, NotEmpty, Single / Single(predicate), Distinct, All / All (indexed), Collection |
| delegate | Throws<T> / Throws(type), ThrowsAny<T> (optional exception predicate); same names on the Func<Task> result for async |
String Contains / DoesNotContain default to StringComparison.Ordinal.
IEnumerable<T> assertions are reached via Assert.ThatSequence(...), delegate
assertions via Assert.ThatAction(...); sequence equality is already covered by
Assert.That(seq).Equal(other).
Full reference per family is in docs/.
Build and test
dotnet build
dotnet run --project SweetAssert.Tests
Status
Early and experimental. The assertion surface is partial and the API may change.
Project layout
SweetAssert/
AssertThat.cs Assert.That / ThatSequence / ThatAction entry points
Asserter.cs carrier types (value + comparer / delegate)
AssertNull.cs IsNull / IsNotNull
AssertSame.cs Same / NotSame (reference identity)
AssertBoolean.cs IsTrue / IsFalse (bool and bool?)
AssertString.cs string assertions
AssertIComparable.cs range assertions
AssertIEqualityComparable.cs equality assertions
AssertTolerance.cs numeric / temporal precision & tolerance Equal
AssertEquivalent.cs structural-equivalence assertions
AssertEnumerable.cs IEnumerable<T> assertions
AssertThrows.cs delegate / throw assertions
AssertType.cs runtime-type assertions (IsType, IsAssignableFrom, …)
Intrusive/IntrusiveAssert.cs .Assert extension property
SweetAssert.Tests/ xUnit v3 test project
docs/ per-family reference (start at docs/README.md)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.CSharp (>= 5.9.0)
- xunit.v3.assert (>= 4.0.0)
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 |
|---|