public async Task<RunSummary> RunAsync (VsixTestCase testCase, IMessageBus messageBus, ExceptionAggregator aggregator, object[] constructorArguments) { if (Process == null) { if (!Start ()) { Stop (); if (!Start ()) { Stop (); messageBus.QueueMessage (new TestFailed (new XunitTest (testCase, testCase.DisplayName), 0, string.Format ("Failed to start Visual Studio {0}{1}.", visualStudioVersion, rootSuffix), new TimeoutException ())); return new RunSummary { Failed = 1, }; } } } if (runner == null) { var hostUrl = RemotingUtil.GetHostUri (pipeName); var clientPipeName = Guid.NewGuid ().ToString ("N"); clientChannel = RemotingUtil.CreateChannel (Constants.ClientChannelName + clientPipeName, clientPipeName); try { runner = (IVsRemoteRunner)RemotingServices.Connect (typeof (IVsRemoteRunner), hostUrl); // We don't require restart anymore since we write to the registry directly the binding paths, // rather than installing a VSIX //if (runner.ShouldRestart ()) { // Stop (); // return await RunAsync (testCase, messageBus, aggregator, constructorArguments); //} if (Debugger.IsAttached) { // Add default trace listeners to the remote process. foreach (var listener in Trace.Listeners.OfType<TraceListener> ()) { runner.AddListener (listener); } } } catch (Exception ex) { messageBus.QueueMessage (new TestFailed (new XunitTest (testCase, testCase.DisplayName), 0, ex.Message, ex)); return new RunSummary { Failed = 1 }; } } var xunitTest = new XunitTest (testCase, testCase.DisplayName); try { var outputHelper = constructorArguments.OfType<TestOutputHelper> ().FirstOrDefault (); if (outputHelper != null) outputHelper.Initialize (messageBus, xunitTest); // Special case for test output, since it's not MBR. var args = constructorArguments.Select (arg => { var helper = arg as ITestOutputHelper; if (helper != null) { var remoteHeper = new RemoteTestOutputHelper (helper); remoteObjects.Add (remoteHeper); return remoteHeper; } return arg; }).ToArray (); var remoteBus = new RemoteMessageBus (messageBus); remoteObjects.Add (remoteBus); var summary = await System.Threading.Tasks.Task.Run ( () => runner.Run (testCase, remoteBus, args)) .TimeoutAfter (testCase.TimeoutSeconds * 1000); // Dump output only if a debugger is attached, meaning that most likely // there is a single test being run/debugged. if (Debugger.IsAttached && outputHelper != null && !string.IsNullOrEmpty (outputHelper.Output)) { Trace.WriteLine (outputHelper.Output); Debugger.Log (0, "", outputHelper.Output); Console.WriteLine (outputHelper.Output); } if (summary.Exception != null) aggregator.Add (summary.Exception); return summary.ToRunSummary (); } catch (Exception ex) { aggregator.Add (ex); messageBus.QueueMessage (new TestFailed (xunitTest, 0, ex.Message, ex)); return new RunSummary { Failed = 1 }; } finally { var outputHelper = constructorArguments.OfType<TestOutputHelper> ().FirstOrDefault (); if (outputHelper != null) outputHelper.Uninitialize (); } }
private static async Task RunTestClassAsync(IMessageBus messageBus, ITestCollection collection, Dictionary<Type, object> collectionFixtureMappings, IReflectionTypeInfo testClass, IEnumerable<XunitTestCase> testCases, ITestCaseOrderer orderer, RunSummary classSummary, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) { var testClassType = testClass.Type; var fixtureMappings = new Dictionary<Type, object>(); var constructorArguments = new List<object>(); var ordererAttribute = testClass.GetCustomAttributes(typeof(TestCaseOrdererAttribute)).SingleOrDefault(); if (ordererAttribute != null) orderer = GetTestCaseOrderer(ordererAttribute); if (testClassType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICollectionFixture<>))) aggregator.Add(new TestClassException("A test class may not be decorated with ICollectionFixture<> (decorate the test collection class instead).")); foreach (var interfaceType in testClassType.GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IClassFixture<>))) CreateFixture(interfaceType, aggregator, fixtureMappings); if (collection.CollectionDefinition != null) { var declarationType = ((IReflectionTypeInfo)collection.CollectionDefinition).Type; foreach (var interfaceType in declarationType.GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IClassFixture<>))) CreateFixture(interfaceType, aggregator, fixtureMappings); } var isStaticClass = testClassType.IsAbstract && testClassType.IsSealed; if (!isStaticClass) { var ctors = testClassType.GetConstructors(); if (ctors.Length != 1) { aggregator.Add(new TestClassException("A test class may only define a single public constructor.")); } else { var ctor = ctors.Single(); var unusedArguments = new List<string>(); foreach (var paramInfo in ctor.GetParameters()) { object fixture; if (fixtureMappings.TryGetValue(paramInfo.ParameterType, out fixture) || collectionFixtureMappings.TryGetValue(paramInfo.ParameterType, out fixture)) constructorArguments.Add(fixture); else unusedArguments.Add(String.Format("{0} {1}", paramInfo.ParameterType.Name, paramInfo.Name)); } if (unusedArguments.Count > 0) aggregator.Add(new TestClassException("The following constructor arguments did not have matching fixture data: " + String.Join(", ", unusedArguments))); } } var orderedTestCases = orderer.OrderTestCases(testCases); var methodGroups = orderedTestCases.GroupBy(tc => tc.Method); foreach (var method in methodGroups) { if (!messageBus.QueueMessage(new TestMethodStarting(collection, testClass.Name, method.Key.Name))) cancellationTokenSource.Cancel(); else await RunTestMethodAsync(messageBus, constructorArguments.ToArray(), method, classSummary, aggregator, cancellationTokenSource); if (!messageBus.QueueMessage(new TestMethodFinished(collection, testClass.Name, method.Key.Name))) cancellationTokenSource.Cancel(); if (cancellationTokenSource.IsCancellationRequested) break; } foreach (var fixture in fixtureMappings.Values.OfType<IDisposable>()) { try { fixture.Dispose(); } catch (Exception ex) { if (!messageBus.QueueMessage(new ErrorMessage(ex.Unwrap()))) cancellationTokenSource.Cancel(); } } }
/// <summary> /// Runs a single test for a given test method. /// </summary> /// <param name="messageSink">The message sink to send results to.</param> /// <param name="classUnderTest">The class under test.</param> /// <param name="constructorArguments">The arguments to pass to the constructor.</param> /// <param name="methodUnderTest">The method under test.</param> /// <param name="testMethodArguments">The arguments to pass to the test method.</param> /// <param name="displayName">The display name for the test.</param> /// <param name="beforeAfterAttributes">The <see cref="BeforeAfterTestAttribute"/> instances attached to the test.</param> /// <param name="parentAggregator">The parent aggregator that contains the exceptions up to this point.</param> /// <param name="cancellationTokenSource">The cancellation token source that indicates whether cancellation has been requested.</param> /// <param name="executionTime">The time spent executing the tests.</param> protected void RunTestWithArguments(IMessageSink messageSink, Type classUnderTest, object[] constructorArguments, MethodInfo methodUnderTest, object[] testMethodArguments, string displayName, List<BeforeAfterTestAttribute> beforeAfterAttributes, ExceptionAggregator parentAggregator, CancellationTokenSource cancellationTokenSource, ref decimal executionTime) { var aggregator = new ExceptionAggregator(parentAggregator); if (!messageSink.OnMessage(new TestStarting(this, displayName))) cancellationTokenSource.Cancel(); else { if (!String.IsNullOrEmpty(SkipReason)) { if (!messageSink.OnMessage(new TestSkipped(this, displayName, SkipReason))) cancellationTokenSource.Cancel(); } else { var beforeAttributesRun = new Stack<BeforeAfterTestAttribute>(); var stopwatch = Stopwatch.StartNew(); if (!aggregator.HasExceptions) aggregator.Run(() => { object testClass = null; if (!methodUnderTest.IsStatic) { if (!messageSink.OnMessage(new TestClassConstructionStarting(this, displayName))) cancellationTokenSource.Cancel(); try { if (!cancellationTokenSource.IsCancellationRequested) testClass = Activator.CreateInstance(classUnderTest, constructorArguments); } finally { if (!messageSink.OnMessage(new TestClassConstructionFinished(this, displayName))) cancellationTokenSource.Cancel(); } } if (!cancellationTokenSource.IsCancellationRequested) { aggregator.Run(() => { foreach (var beforeAfterAttribute in beforeAfterAttributes) { var attributeName = beforeAfterAttribute.GetType().Name; if (!messageSink.OnMessage(new BeforeTestStarting(this, displayName, attributeName))) cancellationTokenSource.Cancel(); else { try { beforeAfterAttribute.Before(methodUnderTest); beforeAttributesRun.Push(beforeAfterAttribute); } finally { if (!messageSink.OnMessage(new BeforeTestFinished(this, displayName, attributeName))) cancellationTokenSource.Cancel(); } } if (cancellationTokenSource.IsCancellationRequested) return; } if (!cancellationTokenSource.IsCancellationRequested) { var parameterTypes = methodUnderTest.GetParameters().Select(p => p.ParameterType).ToArray(); var oldSyncContext = SynchronizationContext.Current; try { var asyncSyncContext = new AsyncTestSyncContext(); SetSynchronizationContext(asyncSyncContext); aggregator.Run(() => { var result = methodUnderTest.Invoke(testClass, ConvertArguments(testMethodArguments ?? EmptyArray, parameterTypes)); var task = result as Task; if (task != null) task.GetAwaiter().GetResult(); else { var ex = asyncSyncContext.WaitForCompletion(); if (ex != null) aggregator.Add(ex); } }); } finally { SetSynchronizationContext(oldSyncContext); } } }); foreach (var beforeAfterAttribute in beforeAttributesRun) { var attributeName = beforeAfterAttribute.GetType().Name; if (!messageSink.OnMessage(new AfterTestStarting(this, displayName, attributeName))) cancellationTokenSource.Cancel(); aggregator.Run(() => beforeAfterAttribute.After(methodUnderTest)); if (!messageSink.OnMessage(new AfterTestFinished(this, displayName, attributeName))) cancellationTokenSource.Cancel(); } } aggregator.Run(() => { IDisposable disposable = testClass as IDisposable; if (disposable != null) { if (!messageSink.OnMessage(new TestClassDisposeStarting(this, displayName))) cancellationTokenSource.Cancel(); try { disposable.Dispose(); } finally { if (!messageSink.OnMessage(new TestClassDisposeFinished(this, displayName))) cancellationTokenSource.Cancel(); } } }); }); stopwatch.Stop(); if (!cancellationTokenSource.IsCancellationRequested) { executionTime = (decimal)stopwatch.Elapsed.TotalSeconds; var exception = aggregator.ToException(); var testResult = exception == null ? (TestResultMessage)new TestPassed(this, displayName, executionTime) : new TestFailed(this, displayName, executionTime, exception); if (!messageSink.OnMessage(testResult)) cancellationTokenSource.Cancel(); } } } if (!messageSink.OnMessage(new TestFinished(this, displayName, executionTime))) cancellationTokenSource.Cancel(); }
/// <summary> /// Runs a single test for a given test method. /// </summary> /// <param name="messageBus">The message bus to send results to.</param> /// <param name="classUnderTest">The class under test.</param> /// <param name="constructorArguments">The arguments to pass to the constructor.</param> /// <param name="methodUnderTest">The method under test.</param> /// <param name="testMethodArguments">The arguments to pass to the test method.</param> /// <param name="displayName">The display name for the test.</param> /// <param name="beforeAfterAttributes">The <see cref="BeforeAfterTestAttribute"/> instances attached to the test.</param> /// <param name="parentAggregator">The parent aggregator that contains the exceptions up to this point.</param> /// <param name="cancellationTokenSource">The cancellation token source that indicates whether cancellation has been requested.</param> protected async Task <decimal> RunTestWithArgumentsAsync(IMessageBus messageBus, Type classUnderTest, object[] constructorArguments, MethodInfo methodUnderTest, object[] testMethodArguments, string displayName, List <BeforeAfterTestAttribute> beforeAfterAttributes, ExceptionAggregator parentAggregator, CancellationTokenSource cancellationTokenSource) { var executionTimeInSeconds = 0.0m; var aggregator = new ExceptionAggregator(parentAggregator); var output = String.Empty; // TODO: Add output facilities for v2 if (!messageBus.QueueMessage(new TestStarting(this, displayName))) { cancellationTokenSource.Cancel(); } else { if (!String.IsNullOrEmpty(SkipReason)) { if (!messageBus.QueueMessage(new TestSkipped(this, displayName, SkipReason))) { cancellationTokenSource.Cancel(); } } else { var beforeAttributesRun = new Stack <BeforeAfterTestAttribute>(); var executionTime = new ExecutionTime(); if (!aggregator.HasExceptions) { await aggregator.RunAsync(async() => { object testClass = null; if (!methodUnderTest.IsStatic) { if (!messageBus.QueueMessage(new TestClassConstructionStarting(this, displayName))) { cancellationTokenSource.Cancel(); } try { if (!cancellationTokenSource.IsCancellationRequested) { executionTime.Aggregate(() => testClass = Activator.CreateInstance(classUnderTest, constructorArguments)); } } finally { if (!messageBus.QueueMessage(new TestClassConstructionFinished(this, displayName))) { cancellationTokenSource.Cancel(); } } } if (!cancellationTokenSource.IsCancellationRequested) { await aggregator.RunAsync(async() => { foreach (var beforeAfterAttribute in beforeAfterAttributes) { var attributeName = beforeAfterAttribute.GetType().Name; if (!messageBus.QueueMessage(new BeforeTestStarting(this, displayName, attributeName))) { cancellationTokenSource.Cancel(); } else { try { executionTime.Aggregate(() => beforeAfterAttribute.Before(methodUnderTest)); beforeAttributesRun.Push(beforeAfterAttribute); } finally { if (!messageBus.QueueMessage(new BeforeTestFinished(this, displayName, attributeName))) { cancellationTokenSource.Cancel(); } } } if (cancellationTokenSource.IsCancellationRequested) { return; } } if (!cancellationTokenSource.IsCancellationRequested) { var parameterTypes = methodUnderTest.GetParameters().Select(p => p.ParameterType).ToArray(); var oldSyncContext = SynchronizationContext.Current; try { var asyncSyncContext = new AsyncTestSyncContext(); SetSynchronizationContext(asyncSyncContext); await aggregator.RunAsync(async() => { await executionTime.AggregateAsync(async() => { var result = methodUnderTest.Invoke(testClass, Reflector.ConvertArguments(testMethodArguments, parameterTypes)); var task = result as Task; if (task != null) { await task; } else { var ex = await asyncSyncContext.WaitForCompletionAsync(); if (ex != null) { aggregator.Add(ex); } } }); }); } finally { SetSynchronizationContext(oldSyncContext); } } }); foreach (var beforeAfterAttribute in beforeAttributesRun) { var attributeName = beforeAfterAttribute.GetType().Name; if (!messageBus.QueueMessage(new AfterTestStarting(this, displayName, attributeName))) { cancellationTokenSource.Cancel(); } aggregator.Run(() => executionTime.Aggregate(() => beforeAfterAttribute.After(methodUnderTest))); if (!messageBus.QueueMessage(new AfterTestFinished(this, displayName, attributeName))) { cancellationTokenSource.Cancel(); } } } aggregator.Run(() => { var disposable = testClass as IDisposable; if (disposable != null) { if (!messageBus.QueueMessage(new TestClassDisposeStarting(this, displayName))) { cancellationTokenSource.Cancel(); } try { executionTime.Aggregate(disposable.Dispose); } finally { if (!messageBus.QueueMessage(new TestClassDisposeFinished(this, displayName))) { cancellationTokenSource.Cancel(); } } } }); }); } if (!cancellationTokenSource.IsCancellationRequested) { executionTimeInSeconds = (decimal)executionTime.Total.TotalSeconds; var exception = aggregator.ToException(); var testResult = exception == null ? (TestResultMessage) new TestPassed(this, displayName, executionTimeInSeconds, output) : new TestFailed(this, displayName, executionTimeInSeconds, output, exception); if (!messageBus.QueueMessage(testResult)) { cancellationTokenSource.Cancel(); } } } } if (!messageBus.QueueMessage(new TestFinished(this, displayName, executionTimeInSeconds, output))) { cancellationTokenSource.Cancel(); } return(executionTimeInSeconds); }
private static void RunTestClass(IMessageBus messageBus, ITestCollection collection, Dictionary <Type, object> collectionFixtureMappings, IReflectionTypeInfo testClass, IEnumerable <XunitTestCase> testCases, ITestCaseOrderer orderer, RunSummary classSummary, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) { var testClassType = testClass.Type; var fixtureMappings = new Dictionary <Type, object>(); var constructorArguments = new List <object>(); var ordererAttribute = testClass.GetCustomAttributes(typeof(TestCaseOrdererAttribute)).SingleOrDefault(); if (ordererAttribute != null) { orderer = GetTestCaseOrderer(ordererAttribute); } if (testClassType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICollectionFixture <>))) { aggregator.Add(new TestClassException("A test class may not be decorated with ICollectionFixture<> (decorate the test collection class instead).")); } foreach (var interfaceType in testClassType.GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IClassFixture <>))) { CreateFixture(interfaceType, aggregator, fixtureMappings); } if (collection.CollectionDefinition != null) { var declarationType = ((IReflectionTypeInfo)collection.CollectionDefinition).Type; foreach (var interfaceType in declarationType.GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IClassFixture <>))) { CreateFixture(interfaceType, aggregator, fixtureMappings); } } var isStaticClass = testClassType.IsAbstract && testClassType.IsSealed; if (!isStaticClass) { var ctors = testClassType.GetConstructors(); if (ctors.Length != 1) { aggregator.Add(new TestClassException("A test class may only define a single public constructor.")); } else { var ctor = ctors.Single(); var unusedArguments = new List <string>(); foreach (var paramInfo in ctor.GetParameters()) { object fixture; if (fixtureMappings.TryGetValue(paramInfo.ParameterType, out fixture) || collectionFixtureMappings.TryGetValue(paramInfo.ParameterType, out fixture)) { constructorArguments.Add(fixture); } else { unusedArguments.Add(String.Format("{0} {1}", paramInfo.ParameterType.Name, paramInfo.Name)); } } if (unusedArguments.Count > 0) { aggregator.Add(new TestClassException("The following constructor arguments did not have matching fixture data: " + String.Join(", ", unusedArguments))); } } } var orderedTestCases = orderer.OrderTestCases(testCases); var methodGroups = orderedTestCases.GroupBy(tc => tc.Method); foreach (var method in methodGroups) { if (!messageBus.QueueMessage(new TestMethodStarting(collection, testClass.Name, method.Key.Name))) { cancellationTokenSource.Cancel(); } else { RunTestMethod(messageBus, constructorArguments.ToArray(), method, classSummary, aggregator, cancellationTokenSource); } if (!messageBus.QueueMessage(new TestMethodFinished(collection, testClass.Name, method.Key.Name))) { cancellationTokenSource.Cancel(); } if (cancellationTokenSource.IsCancellationRequested) { break; } } foreach (var fixture in fixtureMappings.Values.OfType <IDisposable>()) { try { fixture.Dispose(); } catch (Exception ex) { if (!messageBus.QueueMessage(new ErrorMessage(ex.Unwrap()))) { cancellationTokenSource.Cancel(); } } } }
private static bool RunTestClass(IMessageSink messageSink, IGrouping<ITypeInfo, XunitTestCase> group, RunSummary classSummary) { bool cancelled = false; var aggregator = new ExceptionAggregator(); Type testClassType = ((IReflectionTypeInfo)group.Key).Type; Dictionary<Type, object> fixtureMappings = new Dictionary<Type, object>(); List<object> constructorArguments = new List<object>(); // TODO: Read class fixtures from test collection foreach (var iface in testClassType.GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IClassFixture<>))) { Type fixtureType = iface.GetGenericArguments().Single(); object fixture = null; aggregator.Run(() => fixture = Activator.CreateInstance(fixtureType)); fixtureMappings.Add(fixtureType, fixture); } var ctors = testClassType.GetConstructors(); if (ctors.Length != 1) { aggregator.Add(new TestClassException("A test class may only define a single public constructor.")); } else { var ctor = ctors.Single(); List<string> unusedArguments = new List<string>(); foreach (var paramInfo in ctor.GetParameters()) { object fixture; if (fixtureMappings.TryGetValue(paramInfo.ParameterType, out fixture)) constructorArguments.Add(fixture); else unusedArguments.Add(paramInfo.ParameterType.Name + " " + paramInfo.Name); } if (unusedArguments.Count > 0) aggregator.Add(new TestClassException("The following constructor arguments did not have matching fixture data: " + String.Join(", ", unusedArguments))); } var methodGroups = group.GroupBy(tc => tc.Method); foreach (var method in methodGroups) { if (!messageSink.OnMessage(new TestMethodStarting { ClassName = group.Key.Name, MethodName = method.Key.Name })) cancelled = true; else cancelled = RunTestMethod(messageSink, constructorArguments.ToArray(), method, classSummary, aggregator); if (!messageSink.OnMessage(new TestMethodFinished { ClassName = group.Key.Name, MethodName = method.Key.Name })) cancelled = true; if (cancelled) break; } foreach (var fixture in fixtureMappings.Values.OfType<IDisposable>()) { try { fixture.Dispose(); } catch (Exception ex) { if (!messageSink.OnMessage(new ErrorMessage(ex.Unwrap()))) cancelled = true; } } return cancelled; }
/// <summary> /// Runs a single test for a given test method. /// </summary> /// <param name="messageBus">The message bus to send results to.</param> /// <param name="classUnderTest">The class under test.</param> /// <param name="constructorArguments">The arguments to pass to the constructor.</param> /// <param name="methodUnderTest">The method under test.</param> /// <param name="testMethodArguments">The arguments to pass to the test method.</param> /// <param name="displayName">The display name for the test.</param> /// <param name="beforeAfterAttributes">The <see cref="BeforeAfterTestAttribute"/> instances attached to the test.</param> /// <param name="parentAggregator">The parent aggregator that contains the exceptions up to this point.</param> /// <param name="cancellationTokenSource">The cancellation token source that indicates whether cancellation has been requested.</param> protected async Task<decimal> RunTestWithArgumentsAsync(IMessageBus messageBus, Type classUnderTest, object[] constructorArguments, MethodInfo methodUnderTest, object[] testMethodArguments, string displayName, List<BeforeAfterTestAttribute> beforeAfterAttributes, ExceptionAggregator parentAggregator, CancellationTokenSource cancellationTokenSource) { var executionTimeInSeconds = 0.0m; var aggregator = new ExceptionAggregator(parentAggregator); var output = String.Empty; // TODO: Add output facilities for v2 if (!messageBus.QueueMessage(new TestStarting(this, displayName))) cancellationTokenSource.Cancel(); else { if (!String.IsNullOrEmpty(SkipReason)) { if (!messageBus.QueueMessage(new TestSkipped(this, displayName, SkipReason))) cancellationTokenSource.Cancel(); } else { var beforeAttributesRun = new Stack<BeforeAfterTestAttribute>(); var executionTime = new ExecutionTime(); if (!aggregator.HasExceptions) await aggregator.RunAsync(async () => { object testClass = null; if (!methodUnderTest.IsStatic) { if (!messageBus.QueueMessage(new TestClassConstructionStarting(this, displayName))) cancellationTokenSource.Cancel(); try { if (!cancellationTokenSource.IsCancellationRequested) executionTime.Aggregate(() => testClass = Activator.CreateInstance(classUnderTest, constructorArguments)); } finally { if (!messageBus.QueueMessage(new TestClassConstructionFinished(this, displayName))) cancellationTokenSource.Cancel(); } } if (!cancellationTokenSource.IsCancellationRequested) { await aggregator.RunAsync(async () => { foreach (var beforeAfterAttribute in beforeAfterAttributes) { var attributeName = beforeAfterAttribute.GetType().Name; if (!messageBus.QueueMessage(new BeforeTestStarting(this, displayName, attributeName))) cancellationTokenSource.Cancel(); else { try { executionTime.Aggregate(() => beforeAfterAttribute.Before(methodUnderTest)); beforeAttributesRun.Push(beforeAfterAttribute); } finally { if (!messageBus.QueueMessage(new BeforeTestFinished(this, displayName, attributeName))) cancellationTokenSource.Cancel(); } } if (cancellationTokenSource.IsCancellationRequested) return; } if (!cancellationTokenSource.IsCancellationRequested) { var parameterTypes = methodUnderTest.GetParameters().Select(p => p.ParameterType).ToArray(); var oldSyncContext = SynchronizationContext.Current; try { var asyncSyncContext = new AsyncTestSyncContext(); SetSynchronizationContext(asyncSyncContext); await aggregator.RunAsync(async () => { await executionTime.AggregateAsync(async () => { var result = methodUnderTest.Invoke(testClass, Reflector.ConvertArguments(testMethodArguments, parameterTypes)); var task = result as Task; if (task != null) await task; else { var ex = await asyncSyncContext.WaitForCompletionAsync(); if (ex != null) aggregator.Add(ex); } }); }); } finally { SetSynchronizationContext(oldSyncContext); } } }); foreach (var beforeAfterAttribute in beforeAttributesRun) { var attributeName = beforeAfterAttribute.GetType().Name; if (!messageBus.QueueMessage(new AfterTestStarting(this, displayName, attributeName))) cancellationTokenSource.Cancel(); aggregator.Run(() => executionTime.Aggregate(() => beforeAfterAttribute.After(methodUnderTest))); if (!messageBus.QueueMessage(new AfterTestFinished(this, displayName, attributeName))) cancellationTokenSource.Cancel(); } } aggregator.Run(() => { var disposable = testClass as IDisposable; if (disposable != null) { if (!messageBus.QueueMessage(new TestClassDisposeStarting(this, displayName))) cancellationTokenSource.Cancel(); try { executionTime.Aggregate(disposable.Dispose); } finally { if (!messageBus.QueueMessage(new TestClassDisposeFinished(this, displayName))) cancellationTokenSource.Cancel(); } } }); }); if (!cancellationTokenSource.IsCancellationRequested) { executionTimeInSeconds = (decimal)executionTime.Total.TotalSeconds; var exception = aggregator.ToException(); var testResult = exception == null ? (TestResultMessage)new TestPassed(this, displayName, executionTimeInSeconds, output) : new TestFailed(this, displayName, executionTimeInSeconds, output, exception); if (!messageBus.QueueMessage(testResult)) cancellationTokenSource.Cancel(); } } } if (!messageBus.QueueMessage(new TestFinished(this, displayName, executionTimeInSeconds, output))) cancellationTokenSource.Cancel(); return executionTimeInSeconds; }