2 using System.Reflection;
3 using System.Collections;
9 /// Helper methods for inspecting a type by reflection.
11 /// Many of these methods take a MemberInfo as an argument to avoid
12 /// duplication, even though certain attributes can only appear on
13 /// specific types of members, like MethodInfo or Type.
15 /// Generally, these methods perform simple utility functions like
16 /// checking for a given attribute. However, some of the methdods
17 /// actually implement policies, which might change at some later
18 /// time. The intent is that policies that may vary among different
19 /// types of test cases or suites should be handled by those types,
20 /// while common decisions are handled here.
24 #region Attribute types used by reflect
26 public static readonly Type TestFixtureType = typeof( TestFixtureAttribute );
27 public static readonly Type TestType = typeof( TestAttribute );
28 public static readonly Type SetUpType = typeof( SetUpAttribute );
29 public static readonly Type TearDownType = typeof( TearDownAttribute );
30 public static readonly Type FixtureSetUpType = typeof( TestFixtureSetUpAttribute );
31 public static readonly Type FixtureTearDownType = typeof( TestFixtureTearDownAttribute );
32 public static readonly Type ExplicitType = typeof( ExplicitAttribute );
33 public static readonly Type CategoryType = typeof( CategoryAttribute );
34 public static readonly Type IgnoreType = typeof( IgnoreAttribute );
35 public static readonly Type ExpectedExceptionType = typeof( ExpectedExceptionAttribute );
36 public static readonly Type SuiteType = typeof( SuiteAttribute );
40 #region Binding flags used by reflect
42 private static readonly BindingFlags InstanceMethods =
43 BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
45 private static readonly BindingFlags StaticMethods =
46 BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly;
48 private static readonly BindingFlags AllMethods =
49 BindingFlags.Public | BindingFlags.NonPublic |
50 BindingFlags.Instance | BindingFlags.Static;
52 private static readonly BindingFlags AllDeclaredMethods =
53 AllMethods | BindingFlags.DeclaredOnly;
57 #region Check for presence of an attribute
59 public static bool HasTestFixtureAttribute(Type type)
61 return type.IsDefined( TestFixtureType, true ); // Inheritable
64 public static bool HasTestAttribute(MethodInfo method)
66 return method.IsDefined( TestType, false );
69 public static bool HasExplicitAttribute(MemberInfo member)
71 return member.IsDefined( ExplicitType, false );
74 public static bool HasCategoryAttribute(MemberInfo member)
76 return member.IsDefined( CategoryType, false );
79 public static bool HasExpectedExceptionAttribute(MethodInfo method)
81 return method.IsDefined( ExpectedExceptionType, false );
84 public static bool HasIgnoreAttribute( MemberInfo member )
86 return member.IsDefined( IgnoreType, false );
89 public static bool HasSuiteAttribute( PropertyInfo property )
91 return property.IsDefined( SuiteType, false );
96 #region Legacy Checks on Names
98 public static bool IsObsoleteTestMethod(MethodInfo methodToCheck)
100 if ( methodToCheck.Name.ToLower().StartsWith("test") )
102 object[] attributes = methodToCheck.GetCustomAttributes( false );
104 foreach( Attribute attribute in attributes )
105 if( attribute is SetUpAttribute ||
106 attribute is TestFixtureSetUpAttribute ||
107 attribute is TearDownAttribute ||
108 attribute is TestFixtureTearDownAttribute )
121 #region Get Attributes
123 public static TestFixtureAttribute GetTestFixtureAttribute( Type type )
125 object[] attributes = type.GetCustomAttributes( TestFixtureType, true );
126 return attributes.Length > 0 ? (TestFixtureAttribute) attributes[0] : null;
129 public static TestAttribute GetTestAttribute( MemberInfo member )
131 object[] attributes = member.GetCustomAttributes( TestType, false );
132 return attributes.Length > 0 ? (TestAttribute)attributes[0] : null;
135 public static IgnoreAttribute GetIgnoreAttribute( MemberInfo member )
137 object[] attributes = member.GetCustomAttributes( IgnoreType, false );
138 return attributes.Length > 0 ? (IgnoreAttribute) attributes[0] : null;
141 public static ExpectedExceptionAttribute GetExpectedExceptionAttribute( MethodInfo method )
143 object[] attributes = method.GetCustomAttributes( ExpectedExceptionType, false);
144 return attributes.Length > 0 ? (ExpectedExceptionAttribute) attributes[0] : null;
149 #region Get Properties of Attributes
151 public static string GetIgnoreReason( MemberInfo member )
153 IgnoreAttribute attribute = GetIgnoreAttribute( member );
154 return attribute == null ? "no reason" : attribute.Reason;
157 public static string GetDescription( MethodInfo method )
159 TestAttribute attribute = GetTestAttribute( method );
160 return attribute == null ? null : attribute.Description;
163 public static string GetDescription( Type fixtureType )
165 TestFixtureAttribute attribute = GetTestFixtureAttribute( fixtureType );
166 return attribute == null ? null : attribute.Description;
171 #region Methods to check validity of a type and its members
174 /// Method to validate that a type is a valid test fixture
176 /// <param name="fixtureType">The type to be checked</param>
177 public static void CheckFixtureType( Type fixtureType )
179 if ( fixtureType.GetConstructor( Type.EmptyTypes ) == null )
180 throw new InvalidTestFixtureException(fixtureType.FullName + " does not have a valid constructor");
182 CheckSetUpTearDownMethod( fixtureType, SetUpType );
183 CheckSetUpTearDownMethod( fixtureType, TearDownType );
184 CheckSetUpTearDownMethod( fixtureType, FixtureSetUpType );
185 CheckSetUpTearDownMethod( fixtureType, FixtureTearDownType );
189 /// This method verifies that a type has no more than one method of a particular
190 /// SetUp or TearDown type and that the method has a correct signature.
192 /// <param name="fixtureType">The type to be checked</param>
193 /// <param name="attributeType">The attribute to check for</param>
194 private static void CheckSetUpTearDownMethod( Type fixtureType, Type attributeType )
197 MethodInfo theMethod = null;
199 foreach(MethodInfo method in fixtureType.GetMethods( AllDeclaredMethods ))
201 if( method.IsDefined( attributeType, false ) )
210 string attributeName = attributeType.Name;
211 if ( attributeName.EndsWith( "Attribute" ) )
212 attributeName = attributeName.Substring(
213 0, attributeName.Length - 9 );
215 throw new InvalidTestFixtureException(
216 string.Format( "{0} has multiple {1} methods",
217 fixtureType.Name, attributeName ) );
220 CheckSetUpTearDownSignature( theMethod );
223 private static void CheckSetUpTearDownSignature( MethodInfo method )
225 if ( method != null )
227 if ( !method.IsPublic && !method.IsFamily || method.IsStatic || method.ReturnType != typeof(void) || method.GetParameters().Length > 0 )
228 throw new InvalidTestFixtureException("Invalid SetUp or TearDown method signature");
233 /// Check the signature of a test method
235 /// <param name="methodToCheck">The method signature to check</param>
236 /// <returns>True if the signature is correct, otherwise false</returns>
237 public static bool IsTestMethodSignatureCorrect(MethodInfo methodToCheck)
240 !methodToCheck.IsStatic
241 && !methodToCheck.IsAbstract
242 && methodToCheck.IsPublic
243 && methodToCheck.GetParameters().Length == 0
244 && methodToCheck.ReturnType.Equals(typeof(void));
249 #region Get Methods of a type
251 // These methods all take an object and assume that the type of the
252 // object was pre-checked so that there are no duplicate methods,
253 // statics, private methods, etc.
255 public static ConstructorInfo GetConstructor( Type fixtureType )
257 return fixtureType.GetConstructor( Type.EmptyTypes );
260 public static MethodInfo GetSetUpMethod( Type fixtureType )
262 return GetMethod( fixtureType, SetUpType );
265 public static MethodInfo GetTearDownMethod(Type fixtureType)
267 return GetMethod(fixtureType, TearDownType );
270 public static MethodInfo GetFixtureSetUpMethod( Type fixtureType )
272 return GetMethod( fixtureType, FixtureSetUpType );
275 public static MethodInfo GetFixtureTearDownMethod( Type fixtureType )
277 return GetMethod( fixtureType, FixtureTearDownType );
280 public static MethodInfo GetMethod( Type fixtureType, Type attributeType )
282 foreach(MethodInfo method in fixtureType.GetMethods( InstanceMethods ) )
284 if( method.IsDefined( attributeType, true ) )
291 public static MethodInfo GetMethod( Type fixtureType, string methodName )
293 foreach(MethodInfo method in fixtureType.GetMethods( InstanceMethods ) )
295 if( method.Name == methodName )
304 #region Get Suite Property
306 public static PropertyInfo GetSuiteProperty( Type testClass )
308 if( testClass != null )
310 PropertyInfo[] properties = testClass.GetProperties( StaticMethods );
311 foreach( PropertyInfo property in properties )
313 if( Reflect.HasSuiteAttribute( property ) )
317 CheckSuiteProperty(property);
319 catch( InvalidSuiteException )
330 private static void CheckSuiteProperty(PropertyInfo property)
332 MethodInfo method = property.GetGetMethod(true);
333 if(method.ReturnType!=typeof(NUnit.Core.TestSuite))
334 throw new InvalidSuiteException("Invalid suite property method signature");
335 if(method.GetParameters().Length>0)
336 throw new InvalidSuiteException("Invalid suite property method signature");
343 public static IList GetCategories( MemberInfo member )
345 object[] attributes = member.GetCustomAttributes( CategoryType, false );
346 IList names = new ArrayList();
348 foreach(CategoryAttribute attribute in attributes)
349 names.Add(attribute.Name);
356 #region Invoke Methods
358 public static object Construct( Type type )
360 ConstructorInfo ctor = GetConstructor( type );
362 throw new InvalidTestFixtureException(type.FullName + " does not have a valid constructor");
364 return ctor.Invoke( Type.EmptyTypes );
367 public static void InvokeMethod( MethodInfo method, object fixture )
373 method.Invoke( fixture, null );
375 catch(TargetInvocationException e)
377 Exception inner = e.InnerException;
378 throw new NunitException("Rethrown",inner);
383 public static void InvokeSetUp( object fixture )
385 MethodInfo method = GetSetUpMethod( fixture.GetType() );
388 InvokeMethod(method, fixture);
392 public static void InvokeTearDown( object fixture )
394 MethodInfo method = GetTearDownMethod( fixture.GetType() );
397 InvokeMethod(method, fixture);
403 #region Private Constructor for static-only class
405 private Reflect() { }