Skip to main content

Getting Started with Assertions

TUnit provides a comprehensive, fluent assertion library that makes your tests readable and expressive. This guide introduces the core concepts and gets you started with writing assertions.

Basic Syntax​

All assertions in TUnit follow a consistent pattern using the Assert.That() method:

await Assert.That(actualValue).IsEqualTo(expectedValue);

The basic flow is:

  1. Start with Assert.That(value)
  2. Chain assertion methods (e.g., .IsEqualTo(), .Contains(), .IsGreaterThan())
  3. Always await the assertion (TUnit's assertions are async)

Why Await?​

TUnit assertions must be awaited. This design enables:

  • Async support: Seamlessly test async operations
  • Rich error messages: Build detailed failure messages during execution
  • Extensibility: Create custom assertions that can perform async operations
// ✅ Correct - awaited
await Assert.That(result).IsEqualTo(42);

// ❌ Wrong - will cause compiler warning
Assert.That(result).IsEqualTo(42);

TUnit includes a built-in analyzer that warns you if you forget to await an assertion.

Assertion Categories​

TUnit provides assertions for all common scenarios:

Equality & Comparison​

await Assert.That(actual).IsEqualTo(expected);
await Assert.That(value).IsNotEqualTo(other);
await Assert.That(score).IsGreaterThan(70);
await Assert.That(age).IsLessThanOrEqualTo(100);
await Assert.That(temperature).IsBetween(20, 30);

Strings​

await Assert.That(message).Contains("Hello");
await Assert.That(filename).StartsWith("test_");
await Assert.That(email).Matches(@"^[\w\.-]+@[\w\.-]+\.\w+$");
await Assert.That(input).IsNotEmpty();

Collections​

await Assert.That(numbers).Contains(42);
await Assert.That(items).HasCount(5);
await Assert.That(list).IsNotEmpty();
await Assert.That(values).All(x => x > 0);

Booleans & Null​

await Assert.That(isValid).IsTrue();
await Assert.That(result).IsNotNull();
await Assert.That(optional).IsDefault();

Exceptions​

await Assert.That(() => DivideByZero())
.Throws<DivideByZeroException>()
.WithMessage("Attempted to divide by zero.");

Type Checking​

await Assert.That(obj).IsTypeOf<MyClass>();
await Assert.That(typeof(Dog)).IsAssignableTo<Animal>();

Chaining Assertions​

Combine multiple assertions on the same value using .And:

await Assert.That(username)
.IsNotNull()
.And.IsNotEmpty()
.And.HasLength().GreaterThan(3)
.And.HasLength().LessThan(20);

Use .Or when any condition can be true:

await Assert.That(statusCode)
.IsEqualTo(200)
.Or.IsEqualTo(201)
.Or.IsEqualTo(204);

Multiple Assertions with Assert.Multiple()​

Group related assertions together so all failures are reported:

await using (Assert.Multiple())
{
await Assert.That(user.FirstName).IsEqualTo("John");
await Assert.That(user.LastName).IsEqualTo("Doe");
await Assert.That(user.Age).IsGreaterThan(18);
await Assert.That(user.Email).IsNotNull();
}

Instead of stopping at the first failure, Assert.Multiple() runs all assertions and reports every failure together.

Member Assertions​

Assert on object properties using .Member():

await Assert.That(person)
.Member(p => p.Name, name => name.IsEqualTo("Alice"))
.And.Member(p => p.Age, age => age.IsGreaterThan(18));

This works with nested properties too:

await Assert.That(order)
.Member(o => o.Customer.Address.City, city => city.IsEqualTo("Seattle");

Working with Collections​

Collections have rich assertion support:

var numbers = new[] { 1, 2, 3, 4, 5 };

// Count and emptiness
await Assert.That(numbers).HasCount(5);
await Assert.That(numbers).IsNotEmpty();

// Membership
await Assert.That(numbers).Contains(3);
await Assert.That(numbers).DoesNotContain(10);

// Predicates
await Assert.That(numbers).All(n => n > 0);
await Assert.That(numbers).Any(n => n == 3);

// Ordering
await Assert.That(numbers).IsInOrder();

// Equivalence (same items, any order)
await Assert.That(numbers).IsEquivalentTo(new[] { 5, 4, 3, 2, 1 });

Returning Values from Assertions​

Some assertions return the value being tested, allowing you to continue working with it:

// HasSingleItem returns the single item
var user = await Assert.That(users).HasSingleItem();
await Assert.That(user.Name).IsEqualTo("Alice");

// Contains with predicate returns the found item
var admin = await Assert.That(users).Contains(u => u.Role == "Admin");
await Assert.That(admin.Permissions).IsNotEmpty();

Custom Expectations​

Use .Satisfies() for custom conditions:

await Assert.That(value).Satisfies(v => v % 2 == 0, "Value must be even");

Or map to a different value before asserting:

await Assert.That(order)
.Satisfies(o => o.Total, total => total > 100);

Common Patterns​

Testing Numeric Ranges​

await Assert.That(score).IsBetween(0, 100);
await Assert.That(temperature).IsGreaterThanOrEqualTo(32);

Testing with Tolerance​

For floating-point comparisons:

await Assert.That(3.14159).IsEqualTo(Math.PI).Within(0.001);

Testing Async Operations​

await Assert.That(async () => await FetchDataAsync())
.Throws<HttpRequestException>();

await Assert.That(longRunningTask).CompletesWithin(TimeSpan.FromSeconds(5));

Testing Multiple Conditions​

await Assert.That(username)
.IsNotNull()
.And.Satisfies(name => name.Length >= 3 && name.Length <= 20,
"Username must be 3-20 characters");

Type Safety​

TUnit's assertions are strongly typed and catch type mismatches at compile time:

int number = 42;
string text = "42";

// ✅ This works - both are ints
await Assert.That(number).IsEqualTo(42);

// ❌ This won't compile - can't compare int to string
// await Assert.That(number).IsEqualTo("42");

Common Mistakes & Best Practices​

Forgetting to Await​

[Test]
public void TestValue()
{
// Compiler warning: assertion not awaited
Assert.That(result).IsEqualTo(42);
}

Problem: Assertion never executes, test always passes even if it should fail.

Comparing Different Types​

int number = 42;
// This won't compile - can't compare int to string
// await Assert.That(number).IsEqualTo("42");

// Or this pattern that converts implicitly
string value = GetValue();
await Assert.That(value).IsEqualTo(42); // Won't compile

Problem: Type mismatches are caught at compile time, preventing runtime surprises.

Collection Ordering​

var items = GetItemsFromDatabase(); // Order not guaranteed
await Assert.That(items).IsEqualTo(new[] { 1, 2, 3 });

Problem: Fails unexpectedly if database returns [3, 1, 2] even though items are equivalent.

await Assert.That(user.FirstName).IsEqualTo("John");
await Assert.That(user.LastName).IsEqualTo("Doe");
await Assert.That(user.Age).IsGreaterThan(18);
// If first assertion fails, you won't see the other failures

Problem: Stops at first failure, hiding other issues.

Next Steps​

Now that you understand the basics, explore specific assertion types:

Quick Reference​

Assertion CategoryExample
EqualityIsEqualTo(), IsNotEqualTo()
ComparisonIsGreaterThan(), IsLessThan(), IsBetween()
Null/DefaultIsNull(), IsNotNull(), IsDefault()
BooleanIsTrue(), IsFalse()
StringsContains(), StartsWith(), Matches()
CollectionsContains(), HasCount(), All(), Any()
ExceptionsThrows<T>(), ThrowsNothing()
TypesIsTypeOf<T>(), IsAssignableTo<T>()
AsyncCompletesWithin(), async exception testing

For a complete list of all assertions, see the specific category pages in the sidebar.