Skip to main content

Type Assertions

TUnit provides comprehensive assertions for testing types and type properties. These assertions work with both runtime values and Type objects themselves.

Value Type Assertions

IsTypeOf<T>

Tests that a value is exactly of a specific type:

[Test]
public async Task Value_Is_Type()
{
object value = "Hello";

await Assert.That(value).IsTypeOf<string>();
}

Works with all types:

[Test]
public async Task Various_Types()
{
await Assert.That(42).IsTypeOf<int>();
await Assert.That(3.14).IsTypeOf<double>();
await Assert.That(true).IsTypeOf<bool>();
await Assert.That(new List<int>()).IsTypeOf<List<int>>();
}

IsAssignableTo<T>

Tests that a type can be assigned to a target type (inheritance/interface):

[Test]
public async Task Type_Is_Assignable()
{
var list = new List<int>();

await Assert.That(list).IsAssignableTo<IList<int>>();
await Assert.That(list).IsAssignableTo<IEnumerable<int>>();
await Assert.That(list).IsAssignableTo<object>();
}

With inheritance:

public class Animal { }
public class Dog : Animal { }

[Test]
public async Task Inheritance_Assignability()
{
var dog = new Dog();

await Assert.That(dog).IsAssignableTo<Animal>();
await Assert.That(dog).IsAssignableTo<Dog>();
await Assert.That(dog).IsAssignableTo<object>();
}

IsNotAssignableTo<T>

Tests that a type cannot be assigned to a target type:

[Test]
public async Task Type_Not_Assignable()
{
var value = 42;

await Assert.That(value).IsNotAssignableTo<string>();
await Assert.That(value).IsNotAssignableTo<double>();
}

Type Object Assertions

All the following assertions work on Type objects directly:

[Test]
public async Task Type_Object_Assertions()
{
var type = typeof(string);

await Assert.That(type).IsClass();
await Assert.That(type).IsNotInterface();
}

Class and Interface

IsClass / IsNotClass

[Test]
public async Task Is_Class()
{
await Assert.That(typeof(string)).IsClass();
await Assert.That(typeof(List<int>)).IsClass();
await Assert.That(typeof(object)).IsClass();

await Assert.That(typeof(IEnumerable)).IsNotClass();
await Assert.That(typeof(int)).IsNotClass(); // Value type
}

IsInterface / IsNotInterface

[Test]
public async Task Is_Interface()
{
await Assert.That(typeof(IEnumerable)).IsInterface();
await Assert.That(typeof(IDisposable)).IsInterface();

await Assert.That(typeof(string)).IsNotInterface();
}

Modifiers

IsAbstract / IsNotAbstract

public abstract class AbstractBase { }
public class Concrete : AbstractBase { }

[Test]
public async Task Is_Abstract()
{
await Assert.That(typeof(AbstractBase)).IsAbstract();
await Assert.That(typeof(Concrete)).IsNotAbstract();
}

IsSealed / IsNotSealed

public sealed class SealedClass { }
public class OpenClass { }

[Test]
public async Task Is_Sealed()
{
await Assert.That(typeof(SealedClass)).IsSealed();
await Assert.That(typeof(string)).IsSealed(); // string is sealed
await Assert.That(typeof(OpenClass)).IsNotSealed();
}

Value Types and Enums

IsValueType / IsNotValueType

[Test]
public async Task Is_Value_Type()
{
await Assert.That(typeof(int)).IsValueType();
await Assert.That(typeof(DateTime)).IsValueType();
await Assert.That(typeof(Guid)).IsValueType();

await Assert.That(typeof(string)).IsNotValueType();
await Assert.That(typeof(object)).IsNotValueType();
}

IsEnum / IsNotEnum

public enum Color { Red, Green, Blue }

[Test]
public async Task Is_Enum()
{
await Assert.That(typeof(Color)).IsEnum();
await Assert.That(typeof(DayOfWeek)).IsEnum();

await Assert.That(typeof(int)).IsNotEnum();
}

IsPrimitive / IsNotPrimitive

[Test]
public async Task Is_Primitive()
{
// Primitives: bool, byte, sbyte, short, ushort, int, uint,
// long, ulong, char, double, float, IntPtr, UIntPtr
await Assert.That(typeof(int)).IsPrimitive();
await Assert.That(typeof(bool)).IsPrimitive();
await Assert.That(typeof(char)).IsPrimitive();

await Assert.That(typeof(string)).IsNotPrimitive();
await Assert.That(typeof(decimal)).IsNotPrimitive();
}

Visibility

IsPublic / IsNotPublic

public class PublicClass { }
internal class InternalClass { }

[Test]
public async Task Is_Public()
{
await Assert.That(typeof(PublicClass)).IsPublic();
await Assert.That(typeof(string)).IsPublic();

await Assert.That(typeof(InternalClass)).IsNotPublic();
}

Generics

IsGenericType / IsNotGenericType

[Test]
public async Task Is_Generic_Type()
{
await Assert.That(typeof(List<int>)).IsGenericType();
await Assert.That(typeof(Dictionary<string, int>)).IsGenericType();

await Assert.That(typeof(string)).IsNotGenericType();
}

IsGenericTypeDefinition / IsNotGenericTypeDefinition

[Test]
public async Task Is_Generic_Type_Definition()
{
// Generic type definition (unbound)
await Assert.That(typeof(List<>)).IsGenericTypeDefinition();
await Assert.That(typeof(Dictionary<,>)).IsGenericTypeDefinition();

// Constructed generic type (bound)
await Assert.That(typeof(List<int>)).IsNotGenericTypeDefinition();
}

IsConstructedGenericType / IsNotConstructedGenericType

[Test]
public async Task Is_Constructed_Generic_Type()
{
await Assert.That(typeof(List<int>)).IsConstructedGenericType();
await Assert.That(typeof(Dictionary<string, int>)).IsConstructedGenericType();

await Assert.That(typeof(List<>)).IsNotConstructedGenericType();
await Assert.That(typeof(string)).IsNotConstructedGenericType();
}

ContainsGenericParameters / DoesNotContainGenericParameters

[Test]
public async Task Contains_Generic_Parameters()
{
await Assert.That(typeof(List<>)).ContainsGenericParameters();

await Assert.That(typeof(List<int>)).DoesNotContainGenericParameters();
await Assert.That(typeof(string)).DoesNotContainGenericParameters();
}

Arrays and Pointers

IsArray / IsNotArray

[Test]
public async Task Is_Array()
{
await Assert.That(typeof(int[])).IsArray();
await Assert.That(typeof(string[])).IsArray();
await Assert.That(typeof(int[,])).IsArray(); // Multi-dimensional

await Assert.That(typeof(List<int>)).IsNotArray();
}

IsByRef / IsNotByRef

[Test]
public async Task Is_By_Ref()
{
var method = typeof(string).GetMethod(nameof(int.TryParse));
var parameters = method!.GetParameters();
var outParam = parameters.First(p => p.IsOut);

await Assert.That(outParam.ParameterType).IsByRef();
}

IsByRefLike / IsNotByRefLike (.NET 5+)

[Test]
public async Task Is_By_Ref_Like()
{
await Assert.That(typeof(Span<int>)).IsByRefLike();
await Assert.That(typeof(ReadOnlySpan<int>)).IsByRefLike();

await Assert.That(typeof(string)).IsNotByRefLike();
}

IsPointer / IsNotPointer

[Test]
public async Task Is_Pointer()
{
unsafe
{
var intPtr = typeof(int*);
await Assert.That(intPtr).IsPointer();
}

await Assert.That(typeof(int)).IsNotPointer();
}

Nested Types

IsNested / IsNotNested

public class Outer
{
public class Inner { }
}

[Test]
public async Task Is_Nested()
{
await Assert.That(typeof(Outer.Inner)).IsNested();
await Assert.That(typeof(Outer)).IsNotNested();
}

IsNestedPublic / IsNotNestedPublic

public class Container
{
public class PublicNested { }
private class PrivateNested { }
}

[Test]
public async Task Is_Nested_Public()
{
await Assert.That(typeof(Container.PublicNested)).IsNestedPublic();
}

IsNestedPrivate / IsNotNestedPrivate

[Test]
public async Task Is_Nested_Private()
{
var privateType = typeof(Container)
.GetNestedType("PrivateNested", BindingFlags.NonPublic);

await Assert.That(privateType).IsNestedPrivate();
}

IsNestedAssembly / IsNotNestedAssembly

For internal nested types.

IsNestedFamily / IsNotNestedFamily

For protected nested types.

Visibility Checks

IsVisible / IsNotVisible

[Test]
public async Task Is_Visible()
{
await Assert.That(typeof(string)).IsVisible();
await Assert.That(typeof(List<int>)).IsVisible();

// Internal types are not visible
var internalType = Assembly.GetExecutingAssembly()
.GetTypes()
.FirstOrDefault(t => !t.IsPublic && !t.IsNested);

if (internalType != null)
{
await Assert.That(internalType).IsNotVisible();
}
}

COM Interop

IsCOMObject / IsNotCOMObject

[Test]
public async Task Is_COM_Object()
{
await Assert.That(typeof(string)).IsNotCOMObject();
// COM types would return true
}

Practical Examples

Dependency Injection Validation

[Test]
public async Task Service_Implements_Interface()
{
var service = GetService<IUserService>();

await Assert.That(service).IsAssignableTo<IUserService>();
await Assert.That(service).IsNotNull();
}

Plugin System

public interface IPlugin { }

[Test]
public async Task Plugin_Implements_Interface()
{
var pluginType = LoadPluginType();

await Assert.That(pluginType).IsAssignableTo<IPlugin>();
await Assert.That(pluginType).IsClass();
await Assert.That(pluginType).IsNotAbstract();
}

Reflection Testing

[Test]
public async Task Type_Has_Expected_Properties()
{
var type = typeof(User);

await Assert.That(type).IsClass();
await Assert.That(type).IsPublic();
await Assert.That(type).IsNotAbstract();
await Assert.That(type).IsNotSealed();
}

Generic Constraints

[Test]
public async Task Validate_Generic_Constraints()
{
var listType = typeof(List<int>);

await Assert.That(listType).IsGenericType();
await Assert.That(listType).IsAssignableTo<IEnumerable<int>>();
}

Enum Validation

[Test]
public async Task Type_Is_Enum()
{
var statusType = typeof(OrderStatus);

await Assert.That(statusType).IsEnum();
await Assert.That(statusType).IsValueType();
}

Abstract Class Validation

[Test]
public async Task Base_Class_Is_Abstract()
{
var baseType = typeof(BaseRepository);

await Assert.That(baseType).IsClass();
await Assert.That(baseType).IsAbstract();
}

Chaining Type Assertions

[Test]
public async Task Chained_Type_Assertions()
{
var type = typeof(MyService);

await Assert.That(type)
.IsClass()
.And.IsPublic()
.And.IsNotAbstract()
.And.IsNotSealed();
}

Type Comparison

[Test]
public async Task Compare_Types()
{
var type1 = typeof(List<int>);
var type2 = typeof(List<int>);
var type3 = typeof(List<string>);

await Assert.That(type1).IsEqualTo(type2);
await Assert.That(type1).IsNotEqualTo(type3);
}

Working with Base Types

[Test]
public async Task Check_Base_Type()
{
var type = typeof(ArgumentNullException);
var baseType = type.BaseType;

await Assert.That(baseType).IsEqualTo(typeof(ArgumentException));
}

Interface Implementation

[Test]
public async Task Implements_Multiple_Interfaces()
{
var type = typeof(List<int>);

await Assert.That(type).IsAssignableTo<IList<int>>();
await Assert.That(type).IsAssignableTo<ICollection<int>>();
await Assert.That(type).IsAssignableTo<IEnumerable<int>>();
}

Common Patterns

Factory Pattern Validation

[Test]
public async Task Factory_Returns_Correct_Type()
{
var instance = Factory.Create("user-service");

await Assert.That(instance).IsTypeOf<UserService>();
await Assert.That(instance).IsAssignableTo<IService>();
}

ORM Entity Validation

[Test]
public async Task Entity_Is_Properly_Configured()
{
var entityType = typeof(Order);

await Assert.That(entityType).IsClass();
await Assert.That(entityType).IsPublic();
await Assert.That(entityType).IsNotAbstract();

// Check for required interfaces
await Assert.That(entityType).IsAssignableTo<IEntity>();
}

Serialization Requirements

[Test]
public async Task Type_Is_Serializable()
{
var type = typeof(DataTransferObject);

await Assert.That(type).IsClass();
await Assert.That(type).IsPublic();

// All properties should be public
var properties = type.GetProperties();
await Assert.That(properties).All(p => p.GetMethod?.IsPublic ?? false);
}

Test Double Validation

[Test]
public async Task Mock_Implements_Interface()
{
var mock = Mock.Of<IUserRepository>();
var instance = mock.Object;

await Assert.That(instance).IsAssignableTo<IUserRepository>();
}

Struct Validation

public struct Point
{
public int X { get; set; }
public int Y { get; set; }
}

[Test]
public async Task Struct_Properties()
{
var type = typeof(Point);

await Assert.That(type).IsValueType();
await Assert.That(type).IsNotClass();
await Assert.That(type).IsNotEnum();
}

Record Validation

public record Person(string Name, int Age);

[Test]
public async Task Record_Properties()
{
var type = typeof(Person);

await Assert.That(type).IsClass();
// Records are classes with special properties
}

See Also