[英]How to get the name of the instance disposed by using reflection
我正在为我的数据库存储过程构建一些集成测试。 我已经设置了一个 xUnit 项目并实现了 Fixture 模式。 给你看:
public class MyTableTest : IClassFixture<DatabaseFixture>
{
public MyTableTest()
{
//DO SOMETHING
}
[Fact]
public void Test()
{
//DO SOMETHING
}
}
和:
public class DatabaseFixture : IDisposable
{
public void Dispose()
{
// ... clean up test data from the database ...
}
}
这个DatabaseFixture将在我的所有测试类中共享。 为什么? 因为我希望在每次测试结束时发生一些常见的逻辑,例如清理。
重点是我需要知道要清理哪个表,在我的示例中是MyTable 。 当 Dispose 方法将针对正在处理的MyTableTest实例运行时,我将使用反射检索此类信息。 我怎样才能做到这一点? 是否有可能(并且正确)尝试实现这一目标? 提前致谢。
您可以在DatabaseFixture
类中有一个TableName
属性。 然后在测试类的构造函数中接收该类的实例并设置该TableName
属性。 稍后您可以在 dispose 中使用它进行一些清理。
public class MyTableTest : IClassFixture<DatabaseFixture>
{
DatabaseFixture databaseFixture;
public MyTableTest(DatabaseFixture databaseFixture)
{
this.databaseFixture = databaseFixture;
databaseFixture.TableName = "MyTable";
}
[Fact]
public void Test()
{
}
}
public class DatabaseFixture : IDisposable
{
//...
public string TableName { get; set; }
//...
public void Dispose()
{
// Cleanup based on TableName
}
}
要了解有关在 xUnit 中共享上下文的更多信息,请查看:
您可以使用自定义属性将任意数据附加到您的派生 Fixture 类。
例如
TableNameAttribute
:[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class TableNameAttribute : Attribute
{
public string Name { get; }
public TableNameAttribute(string name)
{
this.Name = name;
}
}
[TableName("MyTable")]
public class MyTableFixture : DatabaseFixture { }
public class MyTableTest : IClassFixture<MyTableFixture>
{
[Fact]
public void Test()
{
//DO SOMETHING
}
}
最后,这是从Dispose
方法中检索Name
的方法:
public abstract class DatabaseFixture : IDisposable
{
...
public void Dispose()
{
var attribute = this.GetType().GetCustomAttribute(typeof(TableNameAttribute));
if (attribute is TableNameAttribute tableNameAttr)
Console.WriteLine(tableNameAttr.Name);
}
}
是否有可能(并且正确)尝试实现这一目标?
不。反射不能告诉类型T
在什么上下文中使用T
; 反射只看到T
的声明。
更具体到你的情况,反映不能告诉类型DatabaseFixture
,它被用作泛型接口的类型参数IClassFixture
在声明MyTableTest
。 换句话说,对于这组声明,
class A { }
class B <T> { }
class C : B<A> { }
A
不能反射性地确定它在C
的声明中使用,但C
可以知道它对A
用法:
typeof(C)
.BaseType // B
.GetGenericArguments()[0] // A
我怎样才能做到这一点?
根据您使用DatabaseFixture
,您可以使用StackTrace
获取调用测试类(如果您真的很想使用反射)。 这是一个简单的例子:
public class DisposableObject : System.IDisposable
{
public void Dispose()
{
var stack = new System.Diagnostics.StackTrace();
// This will log the name of the class that instantiated and disposed this.
System.Console.WriteLine(stack.GetFrame(1).GetMethod().DeclaringType.Name);
return;
}
}
如果您DatabaseFixture
不直接从您的测试类调用,你将不得不知道的偏移量传递到GetFrame(int)
或者你需要搜索每个帧,直到找到第一个DeclaringType
符合您的要求(例如, BaseType
是带有通用参数DatabaseFixture
IClassFixture
),如下所示:
System.Type testClassType = new StackTrace()
.GetFrames()
.Where(f =>
{
System.Type baseType = f.GetMethod().DeclaringType.BaseType;
return typeof(IClassFixture<DatabaseFixture>).IsAssignableFrom(baseType);
})
.FirstOrDefault() // First matching result (assuming you found any)
?.GetMethod() // Get the reflected Method
.DeclaringType; // Get the type (e.g. class) that declares this method.
string tableName = testClassType.Name.Replace("Test", "");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.