在C#中,自定义属性(Custom Attributes)是一种强大的机制,可以用来为代码添加元数据。然而,测试这些属性并不总是那么直观。本文将介绍如何使用NUnit测试框架来测试自定义属性。
首先,需要定义一个自定义属性。例如,可以创建一个名为FunkyAttribute
的类,它继承自Attribute
类,并包含一些属性:
public class FunkyAttribute : Attribute
{
public int SettingOne { get; set; }
public string Name { get; set; }
}
这个自定义属性可以被应用于任何程序元素,比如方法:
[Funky(Name = "SomeThingFunkierThanJust_f")]
public static int f() {
return 7;
}
由于自定义属性不是通过调用方法来使用的,因此测试它们需要一种不同的方法。不能简单地调用一个方法并断言结果,而是需要检查属性是否正确地应用到了元素上。
为了测试FunkyAttribute
,可以创建一个测试类:
public class FunkyTester
{
[Test]
[Funky(Name = "RipSnorter")]
public void TestThatNameIsRipSnorter()
{
TestAttrProperty(
new StackFrame().GetMethod(),
"Name",
"RipSnorter"
);
}
[Test]
[Funky(SettingOne = 77)]
public void TestThatSettingOneIs77()
{
TestAttrProperty(
new StackFrame().GetMethod(),
"SettingOne",
77
);
}
private void TestAttrProperty(MethodBase method, string argName, TProp expectedValue)
{
object[] customAttributes = method.GetCustomAttributes(typeof(TAttr), false);
Assert.AreEqual(1, customAttributes.Count());
TAttr attr = (TAttr)customAttributes[0];
PropertyInfo propertyInfo = attr.GetType().GetProperty(argName);
Assert.IsNotNull(propertyInfo);
Assert.AreEqual(typeof(TProp), propertyInfo.PropertyType);
Assert.IsTrue(propertyInfo.CanRead);
Assert.IsTrue(propertyInfo.CanWrite);
Assert.AreEqual(expectedValue, (TProp)propertyInfo.GetValue(attr, null));
}
}
在这个测试类中,定义了两个测试方法,它们都使用了NUnit
的[Test]
属性。还使用了要测试的自定义属性[Funky]
。
自定义属性非常简单,它有一个默认的(无参数)构造函数和两个不同类型的属性,每个属性都有getter和setter。对于每个属性,想要检查:
为了对自定义属性的每个属性执行这些测试,调用了一个帮助方法,即TestAttrProperty
。这个方法是泛型的,因此可以用于任何具有公共getter和setter的自定义属性的属性。它接受一个方法实例的引用(这将始终是一个测试方法),以及属性名和预期值的参数。后者是一个泛型类型参数(TProp
)以及实际自定义属性的类型(TAttr
)。
TestAttrProperty()
然后获取所有与TAttr
类型匹配的自定义属性实例。成功的情况是只有一个!通过限制搜索范围只包括正在测试的自定义属性类型,这意味着NUnit的TestAttribute
实例不会被包括在内,这意味着在测试之前不需要对结果进行过滤。
接下来,使用反射来获取正在测试的属性的PropertyInfo
。然后使用它来执行剩余的测试。