/// <summary> /// Sets the TestScheduler property on the target <paramref name="contextSpecification"/>. /// </summary> /// <param name="contextSpecification"> /// The target context specification instance. /// </param> /// <param name="testScheduler"> /// The test scheduler to apply to <paramref name="contextSpecification"/>. /// </param> /// <exception cref="InvalidOperationException"> /// Thrown when this aspect is applied to a test fixture not defining a TestScheduler property. /// </exception> private static void SetTestScheduler(IContextSpecification contextSpecification, [CanBeNull] TestScheduler testScheduler) { var testSchedulerPropertyInfo = contextSpecification.GetType().GetProperty("TestScheduler", BindingFlags.Instance | BindingFlags.NonPublic); if (testSchedulerPropertyInfo == null) { throw new InvalidOperationException("RxTestSchedulerAspect was applied but the target test fixture does not contain a TestScheduler property."); } Helper.SetPrivateProperty(contextSpecification, "TestScheduler", testScheduler); }
/// <summary> /// Clear the TestScheduler property and all schedulers in <see cref="SchedulerSwitch"/>. /// </summary> private void TeardownTestScheduler(IContextSpecification contextSpecification) { SetTestScheduler(contextSpecification, null); SchedulerSwitch.GetCurrentThreadScheduler = null; SchedulerSwitch.GetDispatcherScheduler = null; SchedulerSwitch.GetImmediateScheduler = null; SchedulerSwitch.GetNewThreadScheduler = null; SchedulerSwitch.GetTaskPoolScheduler = null; SchedulerSwitch.GetThreadPoolScheduler = null; var testPlatformEnlightenmentProvider = (TestPlatformEnlightenmentProvider)PlatformEnlightenmentProvider.Current; testPlatformEnlightenmentProvider.GetTestScheduler = null; }
/// <summary> /// Determines whether TPL tasks will be run on a given <see cref="IContextSpecification"/>. The <paramref name="contextSpecification"/> instance needs to have the <see cref="TplContextAspect"/> aspect applied to it. /// </summary> /// <param name="contextSpecification"> /// The context specification to inspect. /// </param> /// <returns> /// The value defined in <see cref="TplContextAspect.ExecuteTplTasks"/>. /// </returns> /// <exception cref="InvalidOperationException">The <paramref name="contextSpecification"/> instance does not have <see cref="TplContextAspect"/> applied to it.</exception> public static bool WillExecuteTplTasksOn(IContextSpecification contextSpecification) { var tplContextAspect = contextSpecification.GetType() .GetCustomAttributes(typeof(TplContextAspect), true) .Cast<TplContextAspect>() .SingleOrDefault(); if (tplContextAspect == null) { throw new InvalidOperationException(string.Format("The {0} test fixture is missing a {1} attribute!", contextSpecification.GetType().FullName, typeof(TplContextAspect).Name)); } return tplContextAspect.ExecuteTplTasks; }
/// <summary> /// Helper method that runs a <seealso cref="TestScheduler" /> and waits on a task and tries to replicate the handling /// of exceptions that is achieved with the "await" keyword (not wrapping it in an AggregateException). /// </summary> /// <param name="testScheduler">The <seealso cref="TestScheduler" /> used in the <paramref name="contextSpecification" />.</param> /// <param name="contextSpecification">The current test fixture.</param> /// <param name="result">The task to wait on.</param> public static void StartWaiting( [NotNull] this TestScheduler testScheduler, IContextSpecification contextSpecification, Task result) { if (!TplTestHelper.WillExecuteTplTasksOn(contextSpecification)) { return; } testScheduler.StartWaiting(); // Emulate the "await" exception handling behavior result.Wait(contextSpecification); }
/// <summary> /// Constructs an object which has a private constructor. /// </summary> /// <param name="specification"> /// The specification object. /// </param> /// <param name="args"> /// The arguments to pass to the constructor. /// </param> /// <typeparam name="T"> /// The concrete object type. /// </typeparam> /// <returns> /// The constructed object. /// </returns> /// <exception cref="Exception"> /// Returns any exception thrown by <see cref="Activator.CreateInstance(System.Type,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo)"/>. Unwraps <see cref="TargetInvocationException"/>. /// </exception> public static T InstancePrivateObject <T>(this IContextSpecification specification, params object[] args) { try { return((T)Activator.CreateInstance(typeof(T), BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, args, null)); } catch (TargetInvocationException exception) { throw ExceptionEnlightenment.PrepareForRethrow(exception.InnerException); } }
/// <summary> /// Helper method waits on tasks and tries to replicate the handling of exceptions that is achieved with the "await" /// keyword (not wrapping it in an AggregateException). /// </summary> /// <param name="result">The task to wait on.</param> /// <param name="contextSpecification">The current test fixture.</param> public static void Wait( this Task result, IContextSpecification contextSpecification) { if (!TplTestHelper.WillExecuteTplTasksOn(contextSpecification)) { return; } // Emulate the "await" exception handling behavior try { result.Wait(CancellationToken.None); } catch (AggregateException e) { throw e.InnerException; } }
/// <summary> /// Replaces the <see cref="ContextSpecificationBase.PreTestFixtureSetUp"/> method to instantiate the <see cref="TestScheduler"/> /// and configure the <see cref="RxSchedulers.Switch.SchedulerSwitch"/>. /// </summary> private void SetupTestScheduler(IContextSpecification contextSpecification) { Func<IScheduler> unassignedGuardScheduler = () => { throw new InvalidOperationException("Please assign a scheduler to the respective SchedulerSwitch property. No scheduler is currently assigned."); }; SchedulerSwitch.GetCurrentThreadScheduler = unassignedGuardScheduler; SchedulerSwitch.GetDispatcherScheduler = unassignedGuardScheduler; SchedulerSwitch.GetImmediateScheduler = unassignedGuardScheduler; SchedulerSwitch.GetNewThreadScheduler = unassignedGuardScheduler; SchedulerSwitch.GetTaskPoolScheduler = unassignedGuardScheduler; SchedulerSwitch.GetThreadPoolScheduler = unassignedGuardScheduler; // Replace the default IConcurrencyAbstractionLayer through a specialized PlatformEnlightenmentProvider, // in order to be able to leverage our TestScheduler to introduce virtual time everywhere. var testPlatformEnlightenmentProvider = (TestPlatformEnlightenmentProvider)PlatformEnlightenmentProvider.Current; var testScheduler = new ThreadLocal<TestScheduler>(() => new TestScheduler()); testPlatformEnlightenmentProvider.GetTestScheduler = () => testScheduler.Value; SetTestScheduler(contextSpecification, testScheduler.Value); }
/// <summary> /// Replaces the <see cref="ContextSpecificationBase.PreTestFixtureSetUp"/> method to instantiate the <see cref="TestScheduler"/> /// and configure the <see cref="RxSchedulers.Switch.SchedulerSwitch"/>. /// </summary> private void SetupTestScheduler(IContextSpecification contextSpecification) { Func <IScheduler> unassignedGuardScheduler = () => { throw new InvalidOperationException("Please assign a scheduler to the respective SchedulerSwitch property. No scheduler is currently assigned."); }; SchedulerSwitch.GetCurrentThreadScheduler = unassignedGuardScheduler; SchedulerSwitch.GetDispatcherScheduler = unassignedGuardScheduler; SchedulerSwitch.GetImmediateScheduler = unassignedGuardScheduler; SchedulerSwitch.GetNewThreadScheduler = unassignedGuardScheduler; SchedulerSwitch.GetTaskPoolScheduler = unassignedGuardScheduler; SchedulerSwitch.GetThreadPoolScheduler = unassignedGuardScheduler; // Replace the default IConcurrencyAbstractionLayer through a specialized PlatformEnlightenmentProvider, // in order to be able to leverage our TestScheduler to introduce virtual time everywhere. var testPlatformEnlightenmentProvider = (TestPlatformEnlightenmentProvider)PlatformEnlightenmentProvider.Current; var testScheduler = new ThreadLocal <TestScheduler>(() => new TestScheduler()); testPlatformEnlightenmentProvider.GetTestScheduler = () => testScheduler.Value; SetTestScheduler(contextSpecification, testScheduler.Value); }
/// <summary> /// Called by the framework to register the attribute with the context for setup/teardown notifications. /// </summary> /// <param name="contextSpecification"> /// The target context specification instance. /// </param> public abstract void Register(IContextSpecification contextSpecification);
/// <summary> /// Replaces the <see cref="ContextSpecificationBase.PreTestFixtureSetUp"/> method to set the <see cref="TplTestPlatformHelper.TestTaskScheduler"/> as the default scheduler. /// </summary> /// <param name="contextSpecification"> /// The target context specification instance. /// </param> private void SetupTestTaskScheduler(IContextSpecification contextSpecification) { var testTaskScheduler = new TplTestPlatformHelper.TestTaskScheduler(this.ExecuteTplTasks); TplTestPlatformHelper.SetDefaultScheduler(testTaskScheduler); }
/// <summary> /// Called by the framework to register the attribute with the context for setup/teardown notifications. /// </summary> /// <param name="contextSpecification"> /// The target context specification instance. /// </param> public override void Register(IContextSpecification contextSpecification) { contextSpecification.SetupTasks.Add(this.SetupTestTaskScheduler); }
/// <summary> /// Method executed when entering a test method. /// </summary> /// <param name="instance"> The instance of the context specification. </param> /// <param name="methodInfo"> The test method. </param> /// <param name="becauseAction"> The because method. </param> private void OnTestMethodEntry( IContextSpecification instance, MethodBase methodInfo, Action becauseAction) { var isRunningInTheContextOfAnotherTest = instance.ArePrerequisiteTestsRunning; if (isRunningInTheContextOfAnotherTest) { return; } var isRunningPrerequisite = methodInfo.IsDefined(typeof(PrerequisiteAttribute), true); becauseAction(); if (!isRunningPrerequisite) { this.RunPrerequisiteTestsMethod(); } }
/// <summary> /// Called by the framework to register the attribute with the context for setup/teardown notifications. /// </summary> /// <param name="contextSpecification"> /// The target context specification instance. /// </param> public override void Register(IContextSpecification contextSpecification) { contextSpecification.SetupTasks.Add(this.SetupTestScheduler); contextSpecification.TeardownTasks.Add(this.TeardownTestScheduler); }
/// <summary> /// Determines whether TPL tasks will be run on a given <see cref="IContextSpecification"/>. The <paramref name="contextSpecification"/> instance needs to have the <see cref="TplContextAspectAttribute"/> aspect applied to it. /// </summary> /// <param name="contextSpecification"> /// The context specification to inspect. /// </param> /// <returns> /// The value defined in <see cref="TplContextAspectAttribute.ExecuteTplTasks"/>. /// </returns> /// <exception cref="InvalidOperationException">The <paramref name="contextSpecification"/> instance does not have <see cref="TplContextAspectAttribute"/> applied to it.</exception> public static bool WillExecuteTplTasksOn(IContextSpecification contextSpecification) { var tplContextAspectAttribute = contextSpecification.GetType() .GetCustomAttributes(typeof(TplContextAspectAttribute), true) .Cast<TplContextAspectAttribute>() .Single(); return tplContextAspectAttribute.ExecuteTplTasks; }