我尝试根据本文https://www.skyrise.tech/blog/tech/extending-nunit-3-with-command-wrappers/扩展扩展ICommandWrapper
。我发现我也可以扩展TestAttribute
,并且可以正常工作,然后我尝试扩展TestCaseAttribute
:
[AttributeUsage(AttributeTargets.Method), AllowMultiple = true]
public class MyTestCaseAttribute : TestCaseAttribute, IWrapSetUpTearDown
{
private object[] _args;
public MyTestCaseAttribute(params object[] args) : base(args)
{
_args = args;
}
public TestCommand Wrap(TestCommand command)
{
return new MyTestCommand(command, _args);
}
}
MyTestCommand
扩展了DelegatingTestCommand
,就像在文章中一样。
问题是,如果我将多个MyTestCaseAttribute
添加到一个测试方法中,则该测试方法会被MyTestCommand.Execute
的代码多次包装。
[EDIT] 示例:
假设MyTestCommand
看起来像这样:
public abstract class MyCommandDecorator : DelegatingTestCommand
{
public override TestResult Execute(TestExecutionContext context)
private object[] _testCaseArgs;
protected TestCommandDecorator(TestCommand innerCommand, params object[] args) : base(innerCommand)
{
_testCaseArgs = args;
}
public override TestResult Execute(TestExecutionContext context)
{
DoSomething(_testCaseArgs);
return context.CurrentResult = innerCommand.Execute(context);
}
}
假设我用两个[MyTestCase]
属性装饰测试方法:
[MyTestCase(1)]
[MyTestCase(2)]
public void MyTest(int foo)
{
//...
}
所需的行为类似于:
DoSomething(1);
MyTest(1);
DoSomething(2);
MyTest(2);
但是实际行为是:
DoSomething(2)
DoSomething(1)
MyTest(1)
DoSomething(2)
DoSomething(1)
MyTest(1)
答案 0 :(得分:1)
问题的关键是... C#允许您用属性装饰方法或类。但是在NUnit之外不存在单独的测试用例-没有C#等效项-因此您无法装饰它。
IOW,您的两个属性将应用于该方法,并使NUnit使用该方法生成两个测试用例。但是,您的属性还实现了ICommandWrapper,这会导致NUnit包装它生成的任何测试用例。 NUnit的一部分正在寻找创建测试用例,另一部分正在寻找用于包装测试用例的属性。这两个部分完全分开。
这就是NUnit在测试用例方法上使用属性来指示诸如忽略用例之类的原因的原因。它不能使用属性,因为属性将应用于该方法生成的每个测试用例。
希望能解释发生了什么事。
要解决该问题,您的命令包装器应仅将自身应用于由该特定属性实例生成的测试。这意味着您必须参与测试的创建,至少要在您的属性记住对它创建的测试的引用的范围内。这有点复杂,但是您应该查看TestCaseAttribute的代码以了解如何创建测试用例。
答案 1 :(得分:0)
想通了。
除了扩展TestCaseAttribute
之外,我还可以扩展TestAttribute
并获取使用TestCaseAttribute
从标准command.Test.Arguments
传递给包装类的参数。
[AttributeUsage(AttributeTargets.Method), AllowMultiple = true]
public class MyTestAttribute : TestAttribute, IWrapSetUpTearDown
{
public TestCommand Wrap(TestCommand command)
{
return new MyTestCommand(command, command.Test.Arguments);
}
}
[TestCase(1)]
[TestCase(2)]
[MyTest]
public void MyTest(int foo)
{
//...
}