NUnit 自定义超时属性

NUnit custom Timeout Attribute

我正在尝试实现我自己的 Timeout 属性版本,因为如果设置的测试时间到期,我需要 运行 TearDown 但是,我无法弄清楚如何从 Context 或 Command 获取正在执行的内容 - 测试方法或 SetUp (我也想忽略它的执行) 是否有可能实现自定义版本的 Timeout,它只考虑测试本身而不考虑 SetUp 和 TearDown 方法?

是的,可以创建一个如您描述的那样工作的属性。但是,它不能是“TimeoutAttribute 的新版本”,因为该属性已经存在于 NUnit 中。它必须是一个以不同方式编写的新属性。

当前的 TimeoutAttribute 是 NUnit 中较旧的属性实现之一。它本身实际上做的很少。相反,它只是将信息作为测试对象的 属性 留下,稍后由 NUnit 在内部执行。大多数属性现在已经转换为不同的方法,其中属性本身将代码添加到命令结构以进行测试 - 我将其称为“活动属性”以便于参考。

TimeoutAttribute 仍然使用旧样式(如果你愿意,可以称之为“被动”)的根本原因是它实际上做了两件完全不同的事情:

  1. 当它出现在方法上时,它会设置该方法的超时。
  2. 当它出现在 class 或程序集上时,它设置默认超时,当方法没有设置超时时使用。

我认为这种双重用法是一个不幸的设计错误。 (我可以这么说,因为这是我的错误。)它限制了你做你想做的事情的能力。但是,通过完全忽略现有属性,您可以自己创建一个。编码是 non-trivial 但这是我的建议:

  1. 您的属性应实现 IWrapTestMethod 接口。 NUnit 将在适当的时候调用它的 Wrap 方法。

  2. Wrap方法会创建一个派生自TestCommand的对象,它通过在单独的线程上调用基本命令Execute来运行测试方法,并等待为该线程完成。如果它没有在允许的时间内完成,它应该终止线程。

这是不是要编写的简单自定义属性。为此,您必须在属性中创建大量代码。事实上,您将复制大量已在 NUnit 中找到的内容。例如,您需要同时处理同步和异步测试方法,并且需要像 NUnit 一样生成失败结果。

因为涉及面很广,最好在内部修改NUnit。但是,这样的修改很可能是一个突破性的变化,所以我认为不会很快发生。

我想要一个自定义超时属性,它不会在设置超时时中断我的调试。 我的工作版本:

/// <summary>
/// Applies a timeout in milliseconds to a test. 
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class MyTimeoutAttribute: PropertyAttribute, IWrapTestMethod
{
    private const int InfiniteTimeout = Int32.MaxValue;
    private readonly int _timeout;

    public MyTimeoutAttribute(int timeout)
        : base(timeout)
    {
        //if a debugger is attached => disable timeout by setting an infinite one
        _timeout = Debugger.IsAttached ? InfiniteTimeout : timeout;
    }

    public TestCommand Wrap(TestCommand command)
    {
        return new TimeoutCommand(command, _timeout);
    }
}