Null and Default Value Assertions
TUnit provides assertions for testing null values and default values. These assertions integrate with C#'s nullability annotations to provide better compile-time safety.
Null Assertionsâ
IsNullâ
Tests that a value is null:
[Test]
public async Task Null_Value()
{
string? result = GetOptionalValue();
await Assert.That(result).IsNull();
Person? person = FindPerson("unknown-id");
await Assert.That(person).IsNull();
}
IsNotNullâ
Tests that a value is not null:
[Test]
public async Task Not_Null_Value()
{
string? result = GetRequiredValue();
await Assert.That(result).IsNotNull();
var user = GetCurrentUser();
await Assert.That(user).IsNotNull();
}
Nullability Flow Analysisâ
When you use IsNotNull(), C#'s nullability analysis understands that the value is non-null afterward:
[Test]
public async Task Nullability_Flow()
{
string? maybeNull = GetValue();
// After this assertion, compiler knows it's not null
await Assert.That(maybeNull).IsNotNull();
// No warning - compiler knows it's safe
int length = maybeNull.Length;
}
This works with chaining too:
[Test]
public async Task Chained_After_Null_Check()
{
string? input = GetInput();
await Assert.That(input)
.IsNotNull()
.And.IsNotEmpty() // Compiler knows input is not null
.And.Length().IsGreaterThan(5);
}
Default Value Assertionsâ
IsDefaultâ
Tests that a value equals the default value for its type:
[Test]
public async Task Default_Values()
{
// Reference types - default is null
string? text = default;
await Assert.That(text).IsDefault();
// Value types - default is zero/false/empty struct
int number = default;
await Assert.That(number).IsDefault(); // 0
bool flag = default;
await Assert.That(flag).IsDefault(); // false
DateTime date = default;
await Assert.That(date).IsDefault(); // DateTime.MinValue
Guid id = default;
await Assert.That(id).IsDefault(); // Guid.Empty
}
IsNotDefaultâ
Tests that a value is not the default value for its type:
[Test]
public async Task Not_Default_Values()
{
var name = "Alice";
await Assert.That(name).IsNotDefault();
var count = 42;
await Assert.That(count).IsNotDefault();
var isValid = true;
await Assert.That(isValid).IsNotDefault();
var id = Guid.NewGuid();
await Assert.That(id).IsNotDefault();
}
Reference Types vs Value Typesâ
Reference Type Defaultsâ
For reference types, default equals null:
[Test]
public async Task Reference_Type_Defaults()
{
string? text = default;
object? obj = default;
Person? person = default;
await Assert.That(text).IsDefault(); // Same as IsNull()
await Assert.That(obj).IsDefault(); // Same as IsNull()
await Assert.That(person).IsDefault(); // Same as IsNull()
}
Value Type Defaultsâ
For value types, default is the zero-initialized value:
[Test]
public async Task Value_Type_Defaults()
{
// Numeric types default to 0
int intVal = default;
await Assert.That(intVal).IsDefault();
await Assert.That(intVal).IsEqualTo(0);
double doubleVal = default;
await Assert.That(doubleVal).IsDefault();
await Assert.That(doubleVal).IsEqualTo(0.0);
// Boolean defaults to false
bool boolVal = default;
await Assert.That(boolVal).IsDefault();
await Assert.That(boolVal).IsFalse();
// Struct defaults to all fields/properties at their defaults
Point point = default;
await Assert.That(point).IsDefault();
await Assert.That(point).IsEqualTo(new Point(0, 0));
}
Nullable Value Typesâ
Nullable value types (T?) are reference types, so their default is null:
[Test]
public async Task Nullable_Value_Type_Defaults()
{
int? nullableInt = default;
await Assert.That(nullableInt).IsDefault(); // Same as IsNull()
await Assert.That(nullableInt).IsNull(); // Also works
DateTime? nullableDate = default;
await Assert.That(nullableDate).IsDefault();
await Assert.That(nullableDate).IsNull();
}
Practical Examplesâ
Optional Parameters and Returnsâ
[Test]
public async Task Optional_Return_Value()
{
// API might return null if item not found
var item = await _repository.FindByIdAsync("unknown-id");
await Assert.That(item).IsNull();
// API should return value if item exists
var existing = await _repository.FindByIdAsync("valid-id");
await Assert.That(existing).IsNotNull();
}
Initialization Checksâ
[Test]
public async Task Uninitialized_Field()
{
var service = new MyService();
// Before initialization
await Assert.That(service.Connection).IsNull();
await service.InitializeAsync();
// After initialization
await Assert.That(service.Connection).IsNotNull();
}
Dependency Injection Validationâ
[Test]
public async Task Constructor_Injection()
{
var logger = new Mock<ILogger>();
var service = new UserService(logger.Object);
// Verify dependency was injected
await Assert.That(service.Logger).IsNotNull();
}
Lazy Initializationâ
[Test]
public async Task Lazy_Property()
{
var calculator = new ExpensiveCalculator();
// Before first access
await Assert.That(calculator.CachedResult).IsNull();
var result = calculator.GetResult();
// After first access - cached
await Assert.That(calculator.CachedResult).IsNotNull();
}
Checking Multiple Propertiesâ
Use Assert.Multiple() to check multiple null conditions:
[Test]
public async Task Validate_All_Required_Fields()
{
var user = CreateUser();
await using (Assert.Multiple())
{
await Assert.That(user).IsNotNull();
await Assert.That(user.FirstName).IsNotNull();
await Assert.That(user.LastName).IsNotNull();
await Assert.That(user.Email).IsNotNull();
await Assert.That(user.CreatedDate).IsNotDefault();
}
}
Or chain them:
[Test]
public async Task Required_Fields_With_Chaining()
{
var config = LoadConfiguration();
await Assert.That(config.DatabaseConnection)
.IsNotNull()
.And.Member(c => c.Server).IsNotNull()
.And.Member(c => c.Database).IsNotNull();
}
Default Values for Custom Typesâ
Structsâ
public struct Rectangle
{
public int Width { get; init; }
public int Height { get; init; }
}
[Test]
public async Task Struct_Default()
{
Rectangle rect = default;
await Assert.That(rect).IsDefault();
await Assert.That(rect.Width).IsEqualTo(0);
await Assert.That(rect.Height).IsEqualTo(0);
}
Recordsâ
public record Person(string Name, int Age);
[Test]
public async Task Record_Default()
{
Person? person = default;
await Assert.That(person).IsDefault(); // null for reference types
await Assert.That(person).IsNull();
}
public record struct Point(int X, int Y);
[Test]
public async Task Record_Struct_Default()
{
Point point = default;
await Assert.That(point).IsDefault();
await Assert.That(point.X).IsEqualTo(0);
await Assert.That(point.Y).IsEqualTo(0);
}
Special Casesâ
Empty Collections vs Nullâ
[Test]
public async Task Empty_vs_Null()
{
List<string>? nullList = null;
List<string> emptyList = new();
await Assert.That(nullList).IsNull();
await Assert.That(emptyList).IsNotNull();
await Assert.That(emptyList).IsEmpty(); // Not null, but empty
}
Empty Strings vs Nullâ
[Test]
public async Task Empty_String_vs_Null()
{
string? nullString = null;
string emptyString = "";
await Assert.That(nullString).IsNull();
await Assert.That(emptyString).IsNotNull();
await Assert.That(emptyString).IsEmpty(); // Not null, but empty
}
Default GUIDâ
[Test]
public async Task GUID_Default()
{
Guid id = default;
await Assert.That(id).IsDefault();
await Assert.That(id).IsEqualTo(Guid.Empty);
await Assert.That(id).IsEmptyGuid(); // TUnit specific assertion
}
Default DateTimeâ
[Test]
public async Task DateTime_Default()
{
DateTime date = default;
await Assert.That(date).IsDefault();
await Assert.That(date).IsEqualTo(DateTime.MinValue);
}
Combining with Other Assertionsâ
Null Coalescing Validationâ
[Test]
public async Task Null_Coalescing_Default()
{
string? input = GetOptionalInput();
string result = input ?? "default";
if (input == null)
{
await Assert.That(result).IsEqualTo("default");
}
else
{
await Assert.That(result).IsEqualTo(input);
}
}
Null Conditional Operatorâ
[Test]
public async Task Null_Conditional()
{
Person? person = FindPerson("id");
string? name = person?.Name;
if (person == null)
{
await Assert.That(name).IsNull();
}
else
{
await Assert.That(name).IsNotNull();
}
}
Common Patternsâ
Validate Required Dependenciesâ
[Test]
public async Task All_Dependencies_Provided()
{
var service = CreateService();
await Assert.That(service.Logger).IsNotNull();
await Assert.That(service.Repository).IsNotNull();
await Assert.That(service.Cache).IsNotNull();
}
Validate Optional Featuresâ
[Test]
public async Task Optional_Feature_Not_Enabled()
{
var config = LoadConfiguration();
if (!config.EnableAdvancedFeatures)
{
await Assert.That(config.AdvancedSettings).IsNull();
}
}
State Machine Validationâ
[Test]
public async Task State_Transitions()
{
var workflow = new Workflow();
// Initial state
await Assert.That(workflow.CurrentState).IsDefault();
await workflow.StartAsync();
// After start
await Assert.That(workflow.CurrentState).IsNotDefault();
}
See Alsoâ
- Equality & Comparison - Comparing values including defaults
- Boolean Assertions - Testing true/false values
- String Assertions - String-specific null and empty checks
- Collections - Collection null and empty checks