在 .NET 8 中查找堆栈上的 TearDownAttribute 已被破坏

问题描述 投票:0回答:1

背景

我正在开发一些 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
    ),那将非常有帮助
  • 知道如何修复它吗?
c# reflection nunit compiler-optimization .net-8.0
1个回答
0
投票

我只能回答你的第一个问题:

“InvokeStub”是由 Reflection 创建的动态编译代码,源自此处:https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Reflection/ InvokerEmitUtil.cs

© www.soinside.com 2019 - 2024. All rights reserved.