AssertWithIs 1.7.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package AssertWithIs --version 1.7.2
                    
NuGet\Install-Package AssertWithIs -Version 1.7.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AssertWithIs" Version="1.7.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AssertWithIs" Version="1.7.2" />
                    
Directory.Packages.props
<PackageReference Include="AssertWithIs" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add AssertWithIs --version 1.7.2
                    
#r "nuget: AssertWithIs, 1.7.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=AssertWithIs&version=1.7.2
                    
Install as a Cake Addin
#tool nuget:?package=AssertWithIs&version=1.7.2
                    
Install as a Cake Tool

plot

Minimalistic Assertion Extensions for .NET

Simple. Readable. Opinionated.

Is is a lightweight assertion library for .NET that focuses on readable, minimal, and fail-fast test expectations — no assertion clutter, no dependencies, no test framework lock-in.

Why use Is?

  • Concise: One word. One assertion.
  • Opinionated: Less is more. Only core assertions relevant for real-world use cases, just fast failure and clarity.
  • Test-framework agnostic: Works with xUnit, NUnit, MSTest, or none at all.
  • Self-contained: No dependencies, no configuration, just drop it in.
  • Useful for unit tests, guard clauses or other validation checks

📦 Get It on NuGet

NuGet .NET

The package is published on NuGet under the name AssertWithIs because shorter IDs like Is or Is.Assertions were already taken or reserved.
Despite the package name, the library itself uses the concise Is namespace and generates a single Is.dll, so your code stays clean and expressive:

Available Methods

All public methods in Is are:

  • Extension methods, designed to be used fluently (value.Is(...))
  • Named consistently: Every method starts with Is, making them easy to discover with IntelliSense
  • Minimal and deliberate: Only a small, opinionated set of assertions is exposed

Because all methods start with Is, you can type . and just filter by Is in IntelliSense. Fast and frictionless.

The full public API and its extension methods can be found here

Usage Examples

Basic value checks

42.Is(42);       // ✅ passes
42.Is(41);       // ❌ throws Is.NotException: 42 (System.Int32) is not 41 (System.Int32)
42.Is(42.0);     // ❌ throws Is.NotException: 42 (System.Int32) is not 42 (System.Double)

"test".Is("test");               // ✅ passes

Collection checks

new[] { 1, 2, 3 }.Is(1, 2, 3);   // ✅ passes (enumerable values check)

new List<int> { 1, 2, 3, 4, 5, 6 }.Where(i => i % 2 == 0).Is(2, 4, 6);     // ✅ passes
new List<int> { 1, 2, 3, 4, 5, 6 }.Where(i => i % 3 == 0).Is(3, 6);        // ✅ passes
new List<int> { 1, 2, 3, 4, 5, 6 }.Where(i => i % 4 == 0).Is(4);           // ✅ passes

new List<int> { 1, 2, 3, 4 }.IsContaining(1, 2);    // ✅ passes
new List<int> { 1, 2 }.IsIn(1, 2, 3, 4);            // ✅ passes

Type checks

"hello".Is<string>();     // ✅ passes
"hello".Is<int>();        // ❌ throws Is.NotException: "hello" (System.String) is no System.Int32

Numeric comparisons

2.999999f.Is(3f)         // ✅ passes
783.0123.Is(783.0124)    // ✅ passes

5.IsSmallerThan(6);      // ✅ passes
6.IsGreaterThan(5.0);    // ✅ passes
5.IsGreaterThan(6);      // ❌ throws Is.NotException: 5 (System.Int32) is not greater than 6 (System.Int32)
2.IsBetween(1, 3);       // ✅ passes

(0.1 + 0.2).Is(0.3);                // ✅ passes
(0.1 + 0.2).IsExactly(0.3);         // ❌ fails
(0.1 + 0.2).IsApproximately(0.3);   // ✅ passes

(1.0 / 3.0).Is(0.333333);     // ✅ passes
(1.0 / 3.0).Is(0.33333);      // ❌ throws Is.NotException: 0,33333 (System.Double) is not close to 0,3333333333333333 (System.Double)

Exception assertions

static int DivideByZero(int value) => value / 0;
Action action = () => _ = DivideByZero(1);
action.IsThrowing<DivideByZeroException>();  // ✅ passes

Action action = () => 5.IsGreaterThan(6);
action.IsThrowing<Is.NotException>("is not greater than");    // ✅ passes

String checks

var groups = "hello world".IsMatching("(.*) (.*)");  // ✅ passes
groups[1].Value.Is("hello");  // ✅ passes
groups[2].Value.Is("world");  // ✅ passes

"hello world".IsContaining("hello");    // ✅ passes

Error messages

Exception messages

  • uses colors to highlight important parts
  • displays the source of the error (line number and code)

plot

plot

Design Philosophy: Clarity over Chaining

  • No .Should(), no fluent bloat
  • Focus on positive assertions
  • Failure messages like: 42 (System.Int32) is not 41 (System.Int32)
  • Designed to make tests read like intentions, not machinery

Avoid Chaining

While fluent-style chaining such as:

value
    .IsPositive()
    .IsGreaterThan(6)
    .IsBetween(6, 12);

can look elegant, it introduces trade-offs that conflict with design goals:

  • Supporting both chaining and boolean-returning methods would mean duplicating logic, making the library harder to maintain.
  • Useful patterns like .All(x ⇒ x.IsPositive()) require boolean-returning extensions — chaining breaks this.
  • Chaining implies stateful assertion objects; this library favors stateless, minimal assertions for predictability and simplicity.
  • Recommended calling assertions directly and explicitly:
value.IsPositive();
value.IsGreaterThan(6);
value.IsBetween(6, 12);

Enables collection assertion like:

list.All(item => item.IsPositive());

Configuration: Enable/Disable Exception Throwing

The Is library allows users to control whether assertion failures throw exceptions or not. By default, assertion failures throw a NotException. However, you can modify this behavior using the Configuration.ThrowOnFailure flag. If disabled, assertions will instead return false on failure and log the exception message using the configured logger.

Configuration.Logger = Console.WriteLine;

Configuration.ThrowOnFailure = false;

3.Is(4); // ❌

Configuration.ThrowOnFailure = true;

Key Properties

  • ThrowOnFailure: A bool indicating whether assertions throw exceptions on failure. Default is true.
  • Logger: An optional delegate to handle log messages when exceptions are disabled. Defaults to writing messages to System.Diagnostics.Debug.WriteLine.

Grouped Assertion Evaluation with AssertionContext

Sometimes you want to run multiple assertions in a test and evaluate all failures at once, rather than stopping after the first one. The AssertionContext provides exactly that capability.

using var context = AssertionContext.Begin();

false.IsTrue();       // ❌ fails
4.Is(5);              // ❌ fails

context.FailureCount.Is(2);

// You can inspect failures manually:
context.NextFailure().Message.IsContaining("false.IsTrue()");
context.NextFailure().Message.IsContaining("4.Is(5)");

If any assertion failures remain unhandled when the context is disposed, an AggregateException is thrown containing all captured NotExceptions:

try
{
    using var context = AssertionContext.Begin();

    "abc".IsContaining("xyz"); // ❌
    42.Is(0);                  // ❌
}
catch (AggregateException ex)
{
    ex.InnerExceptions.Count.Is(2);
}

Scoped Context:

Only one context can be active per async-flow at a time. It uses AsyncLocal<T> for full async test compatibility.

Designed for Integration:

Works with NUnit, xUnit, or MSTest, either manually via using or with custom test base classes or attributes. To keep the package dependency-free, such implementations are out of scope for the library, but here is an example for such an Attribute for NUnit.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class AssertionContextAttribute
    : NUnitAttribute, NUnit.Framework.Interfaces.IWrapTestMethod
{
    public NUnit.Framework.Internal.Commands.TestCommand Wrap(NUnit.Framework.Internal.Commands.TestCommand command) =>
        new AssertionContextCommand(command);

    private sealed class AssertionContextCommand(NUnit.Framework.Internal.Commands.TestCommand innerCommand)
        : NUnit.Framework.Internal.Commands.DelegatingTestCommand(innerCommand)
    {
        public override NUnit.Framework.Internal.TestResult Execute(NUnit.Framework.Internal.TestExecutionContext testContext)
        {
            var caller = testContext.CurrentTest.Method?.MethodInfo.Name ?? testContext.CurrentTest.Name;

            using var assertionContext = AssertionContext.Begin(caller);

            return innerCommand.Execute(testContext);
        }
    }
}

This allows you to verify NotException like this:

[Test]
[AssertionContext]
public void ContextTest_WithAttribute()
{
    false.IsTrue();
    4.Is(5);

    AssertionContext.Current?.NextFailure();
    AssertionContext.Current?.NextFailure();
}

Custom Assertions

Create a static class with an extension method that performs the desired assertion. Use the built-in Check fluent API to insert the assertion into the features of the library, such as AssertionContext and message formatting.

[IsExtensions]
public static class CustomAssertions
{
    [IsExtension] 
    public static bool IsCustomAssertion(this int value, [CallerArgumentExpression("value")] string? expr = null) => 
        Check.That(value > 0).Unless(value, $"in '{expr}' is not positive");
}

Mark the methods or classes with one of the IsExtension attributes to enable proper user code line detection.

Usage Example

(9 - 5).IsCustomAssertion(); // ✅
(5 - 9).IsCustomAssertion(); // ❌

Results in the following error message:

Is.NotException :

    -4 (Int32)

    in '5 - 9' is not positive

in Is.Tests.Assertions in line 639: (5 - 9).IsCustomAssertion();

Your custom assertions integrate seamlessly with the existing fluent style of the library.

Key Advantages of Is

  • Ultra-Concise Syntax with Natural Readability
  • Minimal Dependencies / Fast Startup
    • Lean and dependency-free — ideal for CI pipelines or constrained environments.
  • Focused on Behavior, Not Chaining
    • Prioritizes clarity over fluent DSL chaining.
  • Extensible and Easy to Maintain
    • Simple to audit, fork, and adapt for your team or test infrastructure.

Architecture

plot

License

MIT – use freely.

Contributing

Ideas, bug reports, or pull requests are always welcome.

Author

Developed with care by chrismo80

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.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.9.1 11 6/30/2025
1.9.0 12 6/30/2025
1.8.1 13 6/28/2025
1.8.0 82 6/26/2025
1.7.3 91 6/25/2025
1.7.2 101 6/25/2025
1.7.1 102 6/25/2025
1.7.0 89 6/21/2025
1.6.0 130 6/19/2025
1.5.0 128 6/19/2025
1.4.0 125 6/18/2025
1.3.4 125 6/17/2025
1.3.3 127 6/16/2025
1.3.2 130 6/16/2025
1.3.1 191 6/8/2025
1.3.0 106 6/7/2025
1.2.0 135 6/5/2025
1.1.0 136 6/4/2025
1.0.0 140 6/2/2025