示例#1
0
        public bool AfterStarting(IMessageBus messageBus, TestStarting message)
        {
            _timer = new ExecutionTimer();
            var testMethod = message.TestMethod.Method.ToRuntimeMethod();

            foreach (var beforeAfterTestCaseAttribute in _beforeAfterAttributes)
            {
                try
                {
                    _timer.Aggregate(() => beforeAfterTestCaseAttribute.Before(testMethod));
                    _attributesStack.Push(beforeAfterTestCaseAttribute);
                }
                catch (Exception e)
                {
                    _exceptions.Add(e);
                }
            }

            return(true);
        }
示例#2
0
        public void OnTestEvent(string report)
        {
            XmlNode xmlNode = XmlHelper.CreateXmlNode(report);

            switch (xmlNode.Name)
            {
            case "start-test":
                TestStarting?.Invoke(new TestNodeEventArgs(TestAction.TestStarting, new TestNode(xmlNode)));
                break;

            case "start-suite":
                SuiteStarting?.Invoke(new TestNodeEventArgs(TestAction.SuiteStarting, new TestNode(xmlNode)));
                break;

            case "start-run":
                RunStarting?.Invoke(new RunStartingEventArgs(xmlNode.GetAttribute("count", -1)));
                break;

            case "test-case":
                ResultNode result = new ResultNode(xmlNode);
                _resultIndex[result.Id] = result;
                TestFinished?.Invoke(new TestResultEventArgs(TestAction.TestFinished, result));
                break;

            case "test-suite":
                result = new ResultNode(xmlNode);
                _resultIndex[result.Id] = result;
                SuiteFinished?.Invoke(new TestResultEventArgs(TestAction.SuiteFinished, result));
                break;

            case "test-run":
                result = new ResultNode(xmlNode);
                _resultIndex[result.Id] = result;
                RunFinished?.Invoke(new TestResultEventArgs(TestAction.RunFinished, result));
                break;
            }
        }
        protected override async Task <RunSummary> RunTestAsync()
        {
            var scenarioFactTestCase = (ScenarioFactTestCase)TestCase;
            var test             = CreateTest(TestCase, DisplayName);
            var aggregatedResult = new RunSummary();

            // Theories are called with required arguments. Keep track of what arguments we already tested so that we can skip those accordingly
            var testedArguments = new HashSet <object>();

            // Each time we find a new theory argument, we will want to restart our Test so that we can collect subsequent test cases
            bool pendingRestart;

            do
            {
                // Safeguarding against abuse
                if (testedArguments.Count >= scenarioFactTestCase.TheoryTestCaseLimit)
                {
                    pendingRestart = false;
                    MessageBus.QueueMessage(new TestSkipped(test, "Theory tests are capped to prevent infinite loops. You can configure a different limit by setting TheoryTestCaseLimit on the Scenario attribute"));
                    aggregatedResult.Aggregate(new RunSummary
                    {
                        Skipped = 1,
                        Total   = 1
                    });
                }
                else
                {
                    var bufferedMessageBus  = new BufferedMessageBus(MessageBus);
                    var stopwatch           = Stopwatch.StartNew();
                    var skipAdditionalTests = false;
                    var testRecorded        = false;
                    pendingRestart = false; // By default we dont expect a new restart

                    object?         capturedArgument = null;
                    ScenarioContext scenarioContext  = null;

                    scenarioContext = new ScenarioContext(scenarioFactTestCase.FactName, async(ScenarioTestCaseDescriptor descriptor) =>
                    {
                        // If we're hitting our target test
                        if (descriptor.Name == scenarioFactTestCase.FactName)
                        {
                            testRecorded = true;

                            if (skipAdditionalTests)
                            {
                                pendingRestart = true; // when we discovered more tests after a test completed, allow us to restart
                                scenarioContext.EndScenarioConditionally();
                                return;
                            }

                            if (descriptor.Argument is not null)
                            {
                                // If we've already received this test case, don't run it again
                                if (testedArguments.Contains(descriptor.Argument))
                                {
                                    return;
                                }

                                testedArguments.Add(descriptor.Argument);
                                capturedArgument = descriptor.Argument;
                            }

                            // At this stage we found our first valid test case, any subsequent test case should issue a restart instead
                            skipAdditionalTests = true;
                            try
                            {
                                await descriptor.Invocation();
                            }
                            catch (Exception)
                            {
                                // If we caught an exception but we're in a theory, we will want to try for additional test cases
                                if (descriptor.Argument is not null)
                                {
                                    pendingRestart = true;
                                }

                                throw;
                            }
                            finally
                            {
                                scenarioContext.IsTargetConclusive = true;
                            }
                        }
                        else
                        {
                            // We may be hitting a shared fact, those need to be invoked as well but not recorded as our primary target
                            if (!scenarioFactTestCase.RunInIsolation || descriptor.Flags.HasFlag(ScenarioTestCaseFlags.Shared))
                            {
                                await descriptor.Invocation();
                            }
                        }
                    });

                    scenarioContext.AutoAbort = scenarioFactTestCase.ExecutionPolicy is ScenarioTestExecutionPolicy.EndAfterConclusion;

                    TestMethodArguments = new object[] { scenarioContext };

                    RunSummary result;

                    result = await CreateTestRunner(test, bufferedMessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, SkipReason, BeforeAfterAttributes, Aggregator, CancellationTokenSource).RunAsync();

                    aggregatedResult.Aggregate(result);

                    stopwatch.Stop();
                    var testInvocationTest = capturedArgument switch
                    {
                        null => CreateTest(TestCase, DisplayName),
                        not null => CreateTest(TestCase, $"{DisplayName} ({capturedArgument})")
                    };

                    var bufferedMessages = bufferedMessageBus.QueuedMessages;

                    // We should have expected at least one test run. We probably returned before our target test was able to run
                    if (!testRecorded && result.Failed == 0)
                    {
                        bufferedMessageBus.QueueMessage(new TestSkipped(test, scenarioContext.SkippedReason ?? "No applicable tests were able to run"));
                        result = new RunSummary {
                            Skipped = 1, Total = 1
                        };
                    }

                    // If we skipped this test, make sure that this is reported accordingly
                    if (scenarioContext.Skipped && !bufferedMessages.OfType <TestSkipped>().Any())
                    {
                        bufferedMessages = bufferedMessages.Concat(new[] { new TestSkipped(testInvocationTest, scenarioContext.SkippedReason) });
                    }

                    // If we have indeed skipped this test, make sure that we're not reporting it as passed or failed
                    if (bufferedMessages.OfType <TestSkipped>().Any())
                    {
                        bufferedMessages = bufferedMessages.Where(x => x is not TestPassed and not TestFailed);
                    }

                    // If we have a failure in post conditions, don't mark this test case as passed
                    if (bufferedMessages.OfType <TestFailed>().Any())
                    {
                        bufferedMessages = bufferedMessages.Where(x => x is not TestPassed);
                    }

                    var output = string.Join("", bufferedMessages
                                             .OfType <ITestOutput>()
                                             .Select(x => x.Output));

                    var duration = (decimal)stopwatch.Elapsed.TotalSeconds;

                    foreach (var queuedMessage in bufferedMessages)
                    {
                        var transformedMessage = queuedMessage switch
                        {
                            TestStarting testStarting => new TestStarting(testInvocationTest),
                            TestSkipped testSkipped => new TestSkipped(testInvocationTest, testSkipped.Reason),
                            TestPassed testPassed => new TestPassed(testInvocationTest, duration, output),
                            TestFailed testFailed => new TestFailed(testInvocationTest, duration, output, testFailed.ExceptionTypes, testFailed.Messages, testFailed.StackTraces, testFailed.ExceptionParentIndices),
                            TestFinished testFinished => new TestFinished(testInvocationTest, duration, output),
                            _ => queuedMessage
                        };

                        if (!MessageBus.QueueMessage(transformedMessage))
                        {
                            return(aggregatedResult);
                        }
                    }
                }
            }while (pendingRestart);

            return(aggregatedResult);
        }
    }
}