Wiki
Clone wikiTypeResolver / Home
.NET Type Resolver
- Used to test all concrete instances of an interface or abstract type.
- Resolves types derived from a class or interface, including generic arguments.
- Implements theory and data attributes for use with xUnit.net.
Release
- 31 January 2018 - Type Resolver v2.3.106 (requires xUnit.net v2.3.1)
- Updated for xUnit.net v2.3.1
- (v2.0.2) Updated MultiMemberDataAttribute
- (v2.0.2) Added TimeoutFact, TimeoutTheory, StaFact, and StaTheory test attributes
- (v2.2.103) Diagnostic error results for load failures
Examples
Basic Use
#!c# interface IFoo { } class Foo1 : IFoo { } class Foo2 : IFoo { } [Theory] [InstanceData] public void TestFoo( IFoo foo ) { // Will be called with instances of both Foo1 and Foo2. }
Multiple Arguments
#!c# public abstract class Bar { } public class Bar1 : Bar { } public class Bar2 : Bar { } [Theory] [InstanceData] public void TestFooBar( IFoo foo, Bar bar ) { // Will be called with all combinations of instances: // - Foo1, Bar1 // - Foo1, Bar2 // - Foo2, Bar1 // - Foo2, Bar2 }
Factories
#!c# // Factory class must be static and being with "Factory". public static class FactoryBaz { // Factory methods must be named "GetInstances" and return "IEnumerable<Func<MyType>>" public static IEnumerable<Func<Baz>> GetInstances( ) { yield return ( ) => Baz.Empty; yield return ( ) => Baz.One; yield return ( ) => Baz.Two; yield return ( ) => Baz.One + Baz.Two; } // Factory methods can also take parameters. public static IEnumerable<Func<Bar>> GetInstances( IFoo foo ) { yield return ( ) => Baz.CreateWithParent( foo ); } // Factory methods can use instance creators to generate multiple, unique instances. public static IEnumerable<Func<Bar>> GetInstances( IInstanceCreator<Pip> pipCreator ) { Pip pip1 = pipCreator.CreateInstance(); yield return ( ) => new Baz( pip1, true ); Pip pip2 = pipCreator.CreateInstance(); yield return ( ) => new Baz( pip2, false ); } } [Theory] [InstanceData] public void TestBaz( Baz bar ) { // Will be called with all factory instances: // - Baz.Empty // - Baz.One // - Baz.Two // - Baz.One + Baz.Two // - Baz.CreateWithParent( Foo1 ) // - Baz.CreateWithParent( Foo2 ) // - new Baz( pip1, true ) // - new Baz( pip2, false ) }
Generic Types
#!c# interface IGru { } interface IGenericGru<T> : IGru { } class IntGru : IGenericGru<int> { } class DoubleGru : IGenericGru<double> { } [Theory] [InstanceData] public void TestGru( IGru gru ) { // Will be called with instances of both IntGru and DoubleGru. }
Generic Methods
#!c# [GenericTheory] [InstanceData] public void TestGru<T>( IGenericGru<T> gru ) { // Will also be called with all Gru instances: // - IntGru (T = int) // - DoubleGru (T = double) } [GenericTheory] [InstanceData] public void TestGru<G>( G gru ) where G : IGru { // Will also be called with all Gru instances: // - IntGru (G = IntGru) // - DoubleGru (G = DoubleGru) } [GenericTheory] [InstanceData] public void TestGru<T, G>( G gru ) where G : IGenericGru<T> { // Will also be called with all Gru instances: // - IntGru (T = int, G = IntGru) // - DoubleGru (T = double, G = DoubleGru) }
Miscellaneous
#!c# public static IEnumerable<object[]> Letters { get { yield return new object[] { "A" }; yield return new object[] { "B" }; } } public static IEnumerable<object[]> Numbers { get { yield return new object[] { 1 }; yield return new object[] { 2 }; } } [Theory] [MultiMemberData( "Letters", "Numbers" )] public void TestLettersAndNumbers( string letter, int number ) { // Will be called with all combinations of PropertyData sources: // - A, 1 // - A, 2 // - B, 1 // - B, 2 }
#!c# // 'Is' extension method can be used on regular or generic types to indicate if they are compatible. int i = 0; i.Is<int>( ); i.Is<ValueType>( ); i.Is( typeof( IComparable<> ) ); var t = typeof( List<int> ); t.Is<List<int>>( ); !t.Is<List<long>>( ); t.Is( typeof( List<> ) ); t.Is( typeof( IEnumerable<> ) ); var g = typeof( List<> ); g.Is( typeof( List<> ) ); g.Is( typeof( List<int> ) ); g.Is( typeof( List<long> ) ); g.Is( typeof( IEnumerable<> ) ); var a = typeof( IDictionary<int,T> ); typeof( IDictionary<,> ).Is( a ); typeof( IDictionary<int,int> ).Is( a ); !typeof( IDictionary<long,long> ).Is( a );
#!c# // 'GetDescriptiveName' extension method returns readable names for generic types, methods, and arguments. Type: typeof( int ) ToString: "System.Int32" GetDescriptiveName: "Int32" Type: typeof( IEnumerable<int> ) ToString: "System.Collections.Generic.IEnumerable`1[System.Int32]" GetDescriptiveName: "IEnumerable<Int32>" Type: typeof( IEnumerable<> ) ToString: "System.Collections.Generic.IEnumerable`1[T]" GetDescriptiveName: "IEnumerable<T>" Type: typeof( IEnumerable<> ).GetGenericArguments( )[0] ToString: "T" GetDescriptiveName: "T on IEnumerable<T>" Method: void Method<T>( T arg ) ToString: "void Method[T](T)" GetDescriptiveName: "Method<T>( T )" Method: int Method<T>( T arg ).GetGenericArguments( )[0] ToString: "T" GetDescriptiveName: "T on Method<T>( T ) : Int32"
Updated