NUnit 自定义超时属性
NUnit custom Timeout Attribute
我正在尝试实现我自己的 Timeout 属性版本,因为如果设置的测试时间到期,我需要 运行 TearDown
但是,我无法弄清楚如何从 Context 或 Command 获取正在执行的内容 - 测试方法或 SetUp (我也想忽略它的执行)
是否有可能实现自定义版本的 Timeout,它只考虑测试本身而不考虑 SetUp 和 TearDown 方法?
是的,可以创建一个如您描述的那样工作的属性。但是,它不能是“TimeoutAttribute 的新版本”,因为该属性已经存在于 NUnit 中。它必须是一个以不同方式编写的新属性。
当前的 TimeoutAttribute
是 NUnit 中较旧的属性实现之一。它本身实际上做的很少。相反,它只是将信息作为测试对象的 属性 留下,稍后由 NUnit 在内部执行。大多数属性现在已经转换为不同的方法,其中属性本身将代码添加到命令结构以进行测试 - 我将其称为“活动属性”以便于参考。
TimeoutAttribute
仍然使用旧样式(如果你愿意,可以称之为“被动”)的根本原因是它实际上做了两件完全不同的事情:
- 当它出现在方法上时,它会设置该方法的超时。
- 当它出现在 class 或程序集上时,它设置默认超时,当方法没有设置超时时使用。
我认为这种双重用法是一个不幸的设计错误。 (我可以这么说,因为这是我的错误。)它限制了你做你想做的事情的能力。但是,通过完全忽略现有属性,您可以自己创建一个。编码是 non-trivial 但这是我的建议:
您的属性应实现 IWrapTestMethod
接口。 NUnit 将在适当的时候调用它的 Wrap
方法。
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);
}
}
我正在尝试实现我自己的 Timeout 属性版本,因为如果设置的测试时间到期,我需要 运行 TearDown 但是,我无法弄清楚如何从 Context 或 Command 获取正在执行的内容 - 测试方法或 SetUp (我也想忽略它的执行) 是否有可能实现自定义版本的 Timeout,它只考虑测试本身而不考虑 SetUp 和 TearDown 方法?
是的,可以创建一个如您描述的那样工作的属性。但是,它不能是“TimeoutAttribute 的新版本”,因为该属性已经存在于 NUnit 中。它必须是一个以不同方式编写的新属性。
当前的 TimeoutAttribute
是 NUnit 中较旧的属性实现之一。它本身实际上做的很少。相反,它只是将信息作为测试对象的 属性 留下,稍后由 NUnit 在内部执行。大多数属性现在已经转换为不同的方法,其中属性本身将代码添加到命令结构以进行测试 - 我将其称为“活动属性”以便于参考。
TimeoutAttribute
仍然使用旧样式(如果你愿意,可以称之为“被动”)的根本原因是它实际上做了两件完全不同的事情:
- 当它出现在方法上时,它会设置该方法的超时。
- 当它出现在 class 或程序集上时,它设置默认超时,当方法没有设置超时时使用。
我认为这种双重用法是一个不幸的设计错误。 (我可以这么说,因为这是我的错误。)它限制了你做你想做的事情的能力。但是,通过完全忽略现有属性,您可以自己创建一个。编码是 non-trivial 但这是我的建议:
您的属性应实现
IWrapTestMethod
接口。 NUnit 将在适当的时候调用它的Wrap
方法。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);
}
}