private TestCommand MakeOneTimeTearDownCommand(List <SetUpTearDownItem> setUpTearDownItems, List <TestActionItem> actions) { TestCommand command = new EmptyTestCommand(Test); // For Theories, follow with TheoryResultCommand to adjust result as needed if (Test.TestType == "Theory") { command = new TheoryResultCommand(command); } // Create the AfterTestAction commands int index = actions.Count; while (--index >= 0) { command = new AfterTestActionCommand(command, actions[index]); } // Create the OneTimeTearDown commands foreach (SetUpTearDownItem item in setUpTearDownItems) { command = new OneTimeTearDownCommand(command, item); } // Dispose of fixture if necessary if (Test is IDisposableFixture && typeof(IDisposable).IsAssignableFrom(Test.TypeInfo.Type)) { command = new DisposeFixtureCommand(command); } return(command); }
/// <summary> /// Creates a test command for use in running this test. /// </summary> /// <returns>A TestCommand</returns> private TestCommand MakeTestCommand() { if (Test.RunState == RunState.Runnable || Test.RunState == RunState.Explicit && Filter.IsExplicitMatch(Test)) { // Command to execute test TestCommand command = new TestMethodCommand(_testMethod); var method = _testMethod.Method; // Add any wrappers to the TestMethodCommand foreach (IWrapTestMethod wrapper in method.GetCustomAttributes <IWrapTestMethod>(true)) { command = wrapper.Wrap(command); } // Create TestActionCommands using attributes of the method foreach (ITestAction action in Test.Actions) { if (action.Targets == ActionTargets.Default || action.Targets.HasFlag(ActionTargets.Test)) { command = new TestActionCommand(command, action); } } ; // Try to locate the parent fixture. In current implementations, the test method // is either one or two levels below the TestFixture - if this changes, // so should the following code. TestFixture parentFixture = Test.Parent as TestFixture ?? Test.Parent?.Parent as TestFixture; // In normal operation we should always get the methods from the parent fixture. // However, some of NUnit's own tests can create a TestMethod without a parent // fixture. Most likely, we should stop doing this, but it affects 100s of cases. var setUpMethods = parentFixture?.SetUpMethods ?? Test.TypeInfo.GetMethodsWithAttribute <SetUpAttribute>(true); var tearDownMethods = parentFixture?.TearDownMethods ?? Test.TypeInfo.GetMethodsWithAttribute <TearDownAttribute>(true); // Wrap in SetUpTearDownCommands var setUpTearDownList = BuildSetUpTearDownList(setUpMethods, tearDownMethods); foreach (var item in setUpTearDownList) { command = new SetUpTearDownCommand(command, item); } // Dispose of fixture if necessary var isInstancePerTestCase = Test.HasLifeCycle(LifeCycle.InstancePerTestCase); if (isInstancePerTestCase && parentFixture is IDisposableFixture && typeof(IDisposable).IsAssignableFrom(parentFixture.TypeInfo.Type)) { command = new DisposeFixtureCommand(command); } // In the current implementation, upstream actions only apply to tests. If that should change in the future, // then actions would have to be tested for here. For now we simply assert it in Debug. We allow // ActionTargets.Default, because it is passed down by ParameterizedMethodSuite. int index = Context.UpstreamActions.Count; while (--index >= 0) { ITestAction action = Context.UpstreamActions[index]; System.Diagnostics.Debug.Assert( action.Targets == ActionTargets.Default || action.Targets.HasFlag(ActionTargets.Test), "Invalid target on upstream action: " + action.Targets.ToString()); command = new TestActionCommand(command, action); } // Add wrappers that apply before setup and after teardown foreach (ICommandWrapper decorator in method.GetCustomAttributes <IWrapSetUpTearDown>(true)) { command = decorator.Wrap(command); } // Add command to set up context using attributes that implement IApplyToContext foreach (var attr in method.GetCustomAttributes <IApplyToContext>(true)) { command = new ApplyChangesToContextCommand(command, attr); } // Add a construct command and optionally a dispose command in case of instance per test case. if (isInstancePerTestCase) { command = new FixturePerTestCaseCommand(command); } // If a timeout is specified, create a TimeoutCommand // Timeout set at a higher level int timeout = Context.TestCaseTimeout; // Timeout set on this test if (Test.Properties.ContainsKey(PropertyNames.Timeout)) { timeout = (int)Test.Properties.Get(PropertyNames.Timeout); } if (timeout > 0) { command = new TimeoutCommand(command, timeout, _debugger); } // Add wrappers for repeatable tests after timeout so the timeout is reset on each repeat foreach (var repeatableAttribute in method.GetCustomAttributes <IRepeatTest>(true)) { command = repeatableAttribute.Wrap(command); } return(command); } else { return(new SkipCommand(_testMethod)); } }