背景
我正在开发一些 NuGet,它们构成了基于 NUnit 的测试自动化基础架构,并在我的整个组织中使用。
作为它的一部分,我有一个方法(让我们称之为
OnTearDown
),它只能从具有 [TearDown]
属性的方法中调用。为了确保这一点,OnTearDown
调用以下方法:
private static void AssertInTearDown(string methodName)
{
var isInTearDown = IsMethodWithAttributeOnStack<TearDownAttribute>();
if (!isInTearDown)
throw new InvalidOperationException(
$"Method {methodName} should only be called from a method with a [TearDown] attribute");
}
private static bool IsMethodWithAttributeOnStack<TAttribute>()
where TAttribute : Attribute
{
var stack = new StackTrace();
return stack.GetFrames().Any(frame => frame.GetMethod()?.HasAttribute<TAttribute>() ?? false);
}
我的一些(老)客户直接调用
OnTearDown
(从他们的 [TearDown]
装饰方法),但我也有一个 TestBase
类,它有自己的 [TearDown]
方法(也称为 TearDown
),大多数新客户使用。
当我们的客户使用 .NET 6 时,一切都运行良好。
问题
最近我们开始将客户端项目和 NuGet 迁移到 .NET 8。有些项目无缝地通过了迁移,但有些项目开始遇到一个非常奇怪的问题。经过调查,我们发现在这些项目中,只要引用项目是 .NET 8,旧版 (.NET 6) 包和新版 (.NET 8) 包都会出现问题。
在这些项目中,一些测试在拆卸时失败,并出现以下错误:
TearDown:System.InvalidOperationException:只能从具有 [TearDown] 属性的方法调用 OnTearDown 方法
堆栈跟踪:
在 AssertInTearDown()
在 OnTearDown()
在 InvokeStub_TestBase.TearDown(对象,对象,IntPtr *)
在 System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(对象 obj,BindingFlags invokeAttr)
注意:为了清楚起见,我在这里修改了真实的堆栈跟踪。
这里最有趣、最可疑的就是上线了
InvokeStub_TestBase.TearDown(Object, Object, IntPtr*)
我真正的类叫做
TestBase
而不是 InvokeStub_TestBase
,并且它没有参数(还有 IntPtr*
...)。我相信 .NET 重新创建了我的 TearDown
方法以进行某种优化,并且由于某种原因它没有 [TearDown]
属性。
我的问题
InvokeStub
),那将非常有帮助我只能回答你的第一个问题:
“InvokeStub”是由 Reflection 创建的动态编译代码,源自此处:https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Reflection/ InvokerEmitUtil.cs