我尝试扩展扩展 ICommandWrapper
,之后:https://www.skyrise.tech/blog/blog/tech/exting-nunit-3-with-with-command-wrappers/。我发现我也可以扩展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
s添加到测试方法中,则多次由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)
问题的关键是... c#允许您装饰具有属性的方法或类。但是,在Nunit之外不存在单个测试用例 - 没有C#等效 - 因此您无法装饰它。
您的两个属性适用于该方法,并导致Nunit使用该方法生成两个测试用例。但是,您的属性还实现了ICommandWrapper,这会导致Nunit包裹其生成的任何测试用例。Nunit的一部分是寻找测试用例来创建另一部分,就是寻找包装测试用例的属性。这两个部分完全分开。
这就是为什么Nunit在测试案例方法上使用属性来指示诸如忽略案例之类的事情。它不能使用属性,因为属性将适用于该方法生成的每个测试用例。
希望这解释了正在发生的事情。
要解决问题,您的命令包装器应仅应用于该属性的特定实例生成的测试。这意味着您必须参与测试的创建,至少在您的属性记住对其创建的测试的引用的程度上。这有点复杂,但是您应该查看testCaseAttribute的代码,以查看如何创建测试案例。
弄清楚了。
,我可以使用command.Test.Arguments
的TestCaseAttribute
S扩展TestAttribute
,而是扩展CC_11并获得将包装程序类传递给包装类别的参数。
[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)
{
//...
}