Expectations for reflection types for aweXpect.
This library contains expectations on reflection types:
You can apply the expectations either on a single type or a collection of types (e.g. Assembly[] or
IEnumerable<Type?>).
The In helper provides powerful filtering capabilities to construct collections of reflection types that match specific criteria. This allows for complex queries across assemblies, types, and their members.
You can select assemblies in various ways:
// All currently loaded assemblies (excluding system assemblies)
In.AllLoadedAssemblies()
// Specific assemblies
In.Assemblies(assembly1, assembly2)
In.Assemblies(assemblyCollection)
// Assembly containing a specific type
In.AssemblyContaining<MyClass>()
In.AssemblyContaining(typeof(MyClass))
// Special assemblies
In.EntryAssembly()
In.ExecutingAssembly()From assemblies, you can navigate to types:
// All types in assemblies
In.AllLoadedAssemblies().Types()
// Specific types
In.Type<MyClass>()
In.Type(typeof(MyClass))
In.Types<Class1, Class2>()
In.Types<Class1, Class2, Class3>()
In.Types(type1, type2, type3)From types, you can navigate to their members:
Type myType = typeof(MyClass);
// Get all members
In.Type(myType).Methods()
In.Type(myType).Properties()
In.Type(myType).Fields()
In.Type(myType).Events()
In.Type(myType).Constructors()
// Navigate back to declaring types from members
In.AllLoadedAssemblies().Methods().DeclaringTypes()You can apply complex filters to narrow down your selections:
// Filter by type characteristics
In.AllLoadedAssemblies().Types()
.WhichAreClasses()
.WhichArePublic()
.WhichAreAbstract()
.WhichAreSealed()
.WhichAreStatic()
.WhichAreGeneric()
.WhichAreNested()
// Alternatively
In.AllLoadedAssemblies().Public.Abstract.Classes()
In.AllLoadedAssemblies().Internal.Generic.Interfaces()
// Filter by name or namespace
In.AllLoadedAssemblies().Types()
.WithName("Service").AsSuffix()
.WithNamespace("MyApp.Services")
// Filter by inheritance
In.AllLoadedAssemblies().Types()
.WhichInheritFrom<BaseClass>()
.WhichInheritFrom(typeof(IInterface))
// Filter by attributes
In.AllLoadedAssemblies().Types()
.With<ObsoleteAttribute>()
.With<DescriptionAttribute>(a => a.Description.Contains("important"))
// Filter by custom predicates
In.AllLoadedAssemblies().Types()
.WhichSatisfy(t => t.Name.StartsWith("Test"))// Filter by method characteristics
In.AllLoadedAssemblies().Methods()
.WhichArePublic()
.WhichArePrivate()
.WhichAreProtected()
.WhichAreInternal()
// Alternatively
In.AllLoadedAssemblies().Public.Methods()
In.AllLoadedAssemblies().Private.Protected.Methods()
// Filter by return types
In.AllLoadedAssemblies().Methods()
.WhichReturn<Task>() // Methods returning Task or Task<T>
.WhichReturnExactly<Task>() // Methods returning exactly Task
.WhichReturn<string>()
// Filter by parameters
In.AllLoadedAssemblies().Methods()
.WithoutParameters()
.WithParameter<string>()
.WithParameter<int>("count")
.WithParameterCount(2)
// Filter by attributes
In.AllLoadedAssemblies().Methods()
.With<TestAttribute>()
.With<ObsoleteAttribute>(a => a.Message != null)
// Filter by name
In.AllLoadedAssemblies().Methods()
.WithName("Get").AsPrefix()
.WithName("Async").AsSuffix()// Properties
In.AllLoadedAssemblies().Public.Properties()
.OfType<string>()
.OfExactType<List<int>>()
.WithName("Id").AsSuffix()
.With<RequiredAttribute>()
// Fields
In.AllLoadedAssemblies().Private.Fields()
.OfType<ILogger>()
.WithName("_").AsPrefix()
.With<NonSerializedAttribute>()
// Events
In.AllLoadedAssemblies().Public.Events()
.WithName("Changed").AsSuffix()
.With<ObsoleteAttribute>()
// Constructors
In.AllLoadedAssemblies().Public.Constructors()
.WithoutParameters()
.WithParameter<string>()
.WithParameterCount(1)
.With<JsonConstructorAttribute>()Filters can be chained and combined using Or methods:
// Multiple attribute options
In.AllLoadedAssemblies().Methods()
.With<FactAttribute>().OrWith<TheoryAttribute>()
// Multiple return type options
In.AllLoadedAssemblies().Methods()
.WhichReturn<Task>().OrReturn<ValueTask>()
// Complex combinations
In.AllLoadedAssemblies().Types()
.WhichAreClasses()
.WhichArePublic()
.WithName("Service").AsSuffix()
.Methods()
.WhichArePublic()
.With<HttpGetAttribute>().OrWith<HttpPostAttribute>()Here are some practical examples of using the In helper:
// Verify all test classes follow naming convention
await Expect.That(In.AllLoadedAssemblies()
.Public.Methods().With<FactAttribute>().OrWith<TheoryAttribute>()
.DeclaringTypes())
.HaveName("Tests").AsSuffix();
// Verify all async methods have "Async" suffix
await Expect.That(In.AssemblyContaining<MyClass>()
.Methods().WhichReturn<Task>().OrReturn<ValueTask>())
.HaveName("Async").AsSuffix();
// Verify all methods with "Async" suffix return Task or ValueTask
await Expect.That(In.AssemblyContaining<MyClass>()
.Methods().WithName("Async").AsSuffix())
.Return<Task>().OrReturn<ValueTask>();
// Verify controllers follow naming convention
await Expect.That(In.AllLoadedAssemblies()
.Types().WhichInheritFrom<ControllerBase>())
.HaveName("Controller").AsSuffix();You can verify the name of an assembly or a collection of assemblies:
Assembly subject = Assembly.GetEntryAssembly();
Assembly[] subjects = AppDomain.CurrentDomain.GetAssemblies();
await Expect.That(subject).HasName("aweXpect.Reflection");
await Expect.That(subjects).HaveName("aweXpect").AsPrefix();You can use the same configuration options as when comparing strings.
You can verify whether assemblies have specific dependencies:
Assembly subject = Assembly.GetEntryAssembly();
Assembly[] subjects = AppDomain.CurrentDomain.GetAssemblies();
// Single assembly
await Expect.That(subject).HasADependencyOn("System.Core");
await Expect.That(subject).HasNoDependencyOn("UnwantedDependency");
// Multiple assemblies
await Expect.That(subjects).HaveADependencyOn("System.Core");
await Expect.That(subjects).HaveNoDependencyOn("UnwantedDependency");You can verify whether assemblies have specific attributes:
Assembly subject = Assembly.GetEntryAssembly();
Assembly[] subjects = AppDomain.CurrentDomain.GetAssemblies();
// Single assembly
await Expect.That(subject).Has<AssemblyTitleAttribute>();
await Expect.That(subject).Has<AssemblyVersionAttribute>(a => a.Version == "1.0.0");
// Multiple assemblies
await Expect.That(subjects).Have<AssemblyTitleAttribute>();You can verify the name or namespace of a type or a collection of types:
Type subject = typeof(MyClass);
IEnumerable<Type> subjects = In.EntryAssembly().Types();
await Expect.That(subject).HasNamespace("aweXpect").AsPrefix();
await Expect.That(subject).HasName("MyClass");
await Expect.That(subjects).HaveNamespace("aweXpect").AsPrefix();
await Expect.That(subjects).HaveName("Tests").AsSuffix();You can use the same configuration options as when comparing strings.
You can verify what kind of type you're dealing with:
Type subject = typeof(MyClass);
IEnumerable<Type> subjects = In.EntryAssembly().Types();
// Single type
await Expect.That(subject).IsAClass();
await Expect.That(subject).IsAnInterface();
await Expect.That(subject).IsAnEnum();
await Expect.That(subject).IsAbstract();
await Expect.That(subject).IsSealed();
await Expect.That(subject).IsStatic();
await Expect.That(subject).IsGeneric();
await Expect.That(subject).IsNested();
// Multiple types
await Expect.That(subjects).AreClasses();
await Expect.That(subjects).AreInterfaces();
await Expect.That(subjects).AreEnums();
await Expect.That(subjects).AreAbstract();
await Expect.That(subjects).AreSealed();
await Expect.That(subjects).AreStatic();
await Expect.That(subjects).AreGeneric();
await Expect.That(subjects).AreNested();
// Negative assertions
await Expect.That(subject).IsNotAClass();
await Expect.That(subject).IsNotAnInterface();
await Expect.That(subject).IsNotAnEnum();
await Expect.That(subject).IsNotAbstract();
await Expect.That(subject).IsNotSealed();
await Expect.That(subject).IsNotStatic();
await Expect.That(subject).IsNotGeneric();
await Expect.That(subject).IsNotNested();
// Multiple types negative assertions
await Expect.That(subjects).AreNotClasses();
await Expect.That(subjects).AreNotInterfaces();
await Expect.That(subjects).AreNotEnums();
await Expect.That(subjects).AreNotAbstract();
await Expect.That(subjects).AreNotSealed();
await Expect.That(subjects).AreNotStatic();
await Expect.That(subjects).AreNotGeneric();
await Expect.That(subjects).AreNotNested();You can verify the access modifiers of types:
Type subject = typeof(MyClass);
IEnumerable<Type> subjects = In.EntryAssembly().Types();
// Single type
await Expect.That(subject).IsPublic();
await Expect.That(subject).IsInternal();
await Expect.That(subject).IsPrivate();
await Expect.That(subject).IsProtected();
// Multiple types
await Expect.That(subjects).ArePublic();
await Expect.That(subjects).AreInternal();
await Expect.That(subjects).ArePrivate();
await Expect.That(subjects).AreProtected();
// Negative assertions
await Expect.That(subject).IsNotPublic();
await Expect.That(subject).IsNotInternal();
await Expect.That(subject).IsNotPrivate();
await Expect.That(subject).IsNotProtected();You can verify whether types have specific attributes:
Type subject = typeof(MyClass);
IEnumerable<Type> subjects = In.EntryAssembly().Types();
// Single type
await Expect.That(subject).Has<ObsoleteAttribute>();
await Expect.That(subject).Has<ObsoleteAttribute>(a => a.Message == "Use NewClass instead");
// Multiple types
await Expect.That(subjects).Have<SerializableAttribute>();You can verify the names of methods:
MethodInfo subject = typeof(MyClass).GetMethod("MyMethod");
IEnumerable<MethodInfo> subjects = typeof(MyClass).GetMethods();
// Single method
await Expect.That(subject).HasName("MyMethod");
// Multiple methods
await Expect.That(subjects).HaveName("Get").AsPrefix();You can verify method parameters:
MethodInfo subject = typeof(MyClass).GetMethod("MyMethod");
IEnumerable<MethodInfo> subjects = typeof(MyClass).GetMethods();
// Single method
await Expect.That(subject).HasParameter<string>();
await Expect.That(subject).HasParameter<string>("parameterName");
await Expect.That(subject).HasParameter("parameterName").OfType<int>();
// Multiple methods
await Expect.That(subjects).HaveParameter<string>();
await Expect.That(subjects).HaveParameter<DateTime>("timestamp");You can verify what methods return:
MethodInfo subject = typeof(MyClass).GetMethod("MyMethod");
IEnumerable<MethodInfo> subjects = typeof(MyClass).GetMethods();
// Single method
await Expect.That(subject).Returns<string>();
await Expect.That(subject).ReturnsExactly<string>(); // Exact type match
await Expect.That(subject).Returns<Task>(); // Also matches Task<T>
await Expect.That(subject).ReturnsExactly<Task>(); // Only matches Task, not Task<T>
// Multiple methods
await Expect.That(subjects).Return<Task>();
await Expect.That(subjects).ReturnExactly<void>();You can verify the access modifiers of methods:
MethodInfo subject = typeof(MyClass).GetMethod("MyMethod");
IEnumerable<MethodInfo> subjects = typeof(MyClass).GetMethods();
// Single method
await Expect.That(subject).IsPublic();
await Expect.That(subject).IsPrivate();
await Expect.That(subject).IsProtected();
await Expect.That(subject).IsInternal();
// Multiple methods
await Expect.That(subjects).ArePublic();
await Expect.That(subjects).ArePrivate();
await Expect.That(subjects).AreProtected();
await Expect.That(subjects).AreInternal();
// Negative assertions
await Expect.That(subject).IsNotPublic();
await Expect.That(subjects).AreNotPrivate();You can verify whether methods have specific attributes:
MethodInfo subject = typeof(MyClass).GetMethod("MyMethod");
IEnumerable<MethodInfo> subjects = typeof(MyClass).GetMethods();
// Single method
await Expect.That(subject).Has<ObsoleteAttribute>();
await Expect.That(subject).Has<DescriptionAttribute>(a => a.Description == "My method");
// Multiple methods
await Expect.That(subjects).Have<AsyncStateMachineAttribute>();You can verify properties by name:
PropertyInfo subject = typeof(MyClass).GetProperty("MyProperty");
IEnumerable<PropertyInfo> subjects = typeof(MyClass).GetProperties();
// Single property
await Expect.That(subject).HasName("MyProperty");
// Multiple properties
await Expect.That(subjects).HaveName("Id").AsSuffix();You can verify the access modifiers of properties:
PropertyInfo subject = typeof(MyClass).GetProperty("MyProperty");
IEnumerable<PropertyInfo> subjects = typeof(MyClass).GetProperties();
// Single property
await Expect.That(subject).IsPublic();
await Expect.That(subject).IsPrivate();
await Expect.That(subject).IsProtected();
await Expect.That(subject).IsInternal();
// Multiple properties
await Expect.That(subjects).ArePublic();
await Expect.That(subjects).AreInternal();
// Negative assertions
await Expect.That(subject).IsNotPrivate();
await Expect.That(subjects).AreNotProtected();You can verify whether properties have specific attributes:
PropertyInfo subject = typeof(MyClass).GetProperty("MyProperty");
IEnumerable<PropertyInfo> subjects = typeof(MyClass).GetProperties();
// Single property
await Expect.That(subject).Has<RequiredAttribute>();
await Expect.That(subject).Has<JsonPropertyNameAttribute>(a => a.Name == "my_property");
// Multiple properties
await Expect.That(subjects).Have<JsonIgnoreAttribute>();You can verify fields by name:
FieldInfo subject = typeof(MyClass).GetField("MyField");
IEnumerable<FieldInfo> subjects = typeof(MyClass).GetFields();
// Single field
await Expect.That(subject).HasName("MyField");
// Multiple fields
await Expect.That(subjects).HaveName("_").AsPrefix();You can verify the access modifiers of fields:
FieldInfo subject = typeof(MyClass).GetField("MyField");
IEnumerable<FieldInfo> subjects = typeof(MyClass).GetFields();
// Single field
await Expect.That(subject).IsPublic();
await Expect.That(subject).IsPrivate();
await Expect.That(subject).IsProtected();
await Expect.That(subject).IsInternal();
// Multiple fields
await Expect.That(subjects).ArePrivate();
// Negative assertions
await Expect.That(subject).IsNotPublic();
await Expect.That(subjects).AreNotPublic();You can verify whether fields have specific attributes:
FieldInfo subject = typeof(MyClass).GetField("MyField");
IEnumerable<FieldInfo> subjects = typeof(MyClass).GetFields();
// Single field
await Expect.That(subject).Has<NonSerializedAttribute>();
// Multiple fields
await Expect.That(subjects).Have<CompilerGeneratedAttribute>();You can verify event names:
EventInfo subject = typeof(MyClass).GetEvent("MyEvent");
IEnumerable<EventInfo> subjects = typeof(MyClass).GetEvents();
// Single event
await Expect.That(subject).HasName("MyEvent");
// Multiple events
await Expect.That(subjects).HaveName("Changed").AsSuffix();You can verify the access modifiers of events:
EventInfo subject = typeof(MyClass).GetEvent("MyEvent");
IEnumerable<EventInfo> subjects = typeof(MyClass).GetEvents();
// Single event
await Expect.That(subject).IsPublic();
await Expect.That(subject).IsPrivate();
await Expect.That(subject).IsProtected();
await Expect.That(subject).IsInternal();
// Multiple events
await Expect.That(subjects).ArePublic();
await Expect.That(subjects).AreInternal();
// Negative assertions
await Expect.That(subject).IsNotPrivate();
await Expect.That(subjects).AreNotProtected();You can verify whether events have specific attributes:
EventInfo subject = typeof(MyClass).GetEvent("MyEvent");
IEnumerable<EventInfo> subjects = typeof(MyClass).GetEvents();
// Single event
await Expect.That(subject).Has<ObsoleteAttribute>();
// Multiple events
await Expect.That(subjects).Have<EditorBrowsableAttribute>();You can verify constructor parameters:
ConstructorInfo subject = typeof(MyClass).GetConstructor(Type.EmptyTypes);
IEnumerable<ConstructorInfo> subjects = typeof(MyClass).GetConstructors();
// Single constructor
await Expect.That(subject).HasParameter<string>();
await Expect.That(subject).HasParameter<string>("name");
// Multiple constructors
await Expect.That(subjects).HaveParameter<ILogger>();You can verify whether constructors have specific attributes:
ConstructorInfo subject = typeof(MyClass).GetConstructor(Type.EmptyTypes);
IEnumerable<ConstructorInfo> subjects = typeof(MyClass).GetConstructors();
// Single constructor
await Expect.That(subject).Has<JsonConstructorAttribute>();
// Multiple constructors
await Expect.That(subjects).Have<ObsoleteAttribute>();When verifying names and other string properties, you have access to the same powerful string matching options as the core aweXpect library:
await Expect.That(type).HasName("MyClass"); // Exact match
await Expect.That(assembly).HasName("MyAssembly"); // Exact matchawait Expect.That(types).HaveName("Test").AsPrefix();
await Expect.That(types).HaveName("Service").AsSuffix();
await Expect.That(types).HaveNamespace("MyApp").AsPrefix();await Expect.That(type).HasName("myclass").IgnoringCase();
await Expect.That(types).HaveName("SERVICE").AsSuffix().IgnoringCase();await Expect.That(types).HaveName("*Test*").AsWildcard();
await Expect.That(methods).HaveName("Get*Async").AsWildcard();await Expect.That(types).HaveName(@"^Test\w+$").AsRegex();
await Expect.That(methods).HaveName(@"^(Get|Set)\w+").AsRegex();All expectations work seamlessly with both single items and collections. When working with collections, you can:
// All types must be classes
await Expect.That(types).AreClasses();
// All methods must be public
await Expect.That(methods).ArePublic();
// All assemblies must have a specific dependency
await Expect.That(assemblies).HaveADependencyOn("System.Core");// At least one type should be abstract
await Expect.That(types).Any().IsAbstract();
// All types should be public
await Expect.That(types).All().ArePublic();
// Exactly 3 methods should have parameters
await Expect.That(methods).Count().Exactly(3).HaveParameter<string>();// Work with filtered collections
var publicMethods = typeof(MyClass).GetMethods().Where(m => m.IsPublic);
await Expect.That(publicMethods).HaveName("Get").AsPrefix();
// Use complex filtering
var complexTypes = In.AllLoadedAssemblies()
.Types()
.WhichAreClasses()
.WhichArePublic()
.Where(t => t.GetInterfaces().Length > 2);
await Expect.That(complexTypes).HaveName("Manager").AsSuffix();By default, system assemblies that start with the following prefixes are excluded from In.AllLoadedAssemblies():
- "mscorlib"
- "System"
- "Microsoft"
- "JetBrains"
- "xunit"
- "Castle"
- "DynamicProxyGenAssembly2"
You can customize this behavior through aweXpect's customization system via Customize.aweXpect.Reflection().ExcludedAssemblyPrefixes.
All expectations are thread-safe and can be used in parallel tests without issues.
- The
Inhelper uses lazy evaluation where possible - Filtering operations are optimized for common scenarios
- Consider caching reflection results if you're performing the same queries repeatedly