public ScenarioInfo(IMethodInfo testMethod, object[] dataRow, string scenarioOutlineDisplayName) { var parameters = testMethod.GetParameters().ToList(); var typeParameters = testMethod.GetGenericArguments().ToList(); ITypeInfo[] typeArguments; if (testMethod.IsGenericMethodDefinition) { typeArguments = typeParameters .Select(typeParameter => InferTypeArgument(typeParameter.Name, parameters, dataRow)) .ToArray(); this.MethodToRun = testMethod.MakeGenericMethod(typeArguments).ToRuntimeMethod(); } else { typeArguments = new ITypeInfo[0]; this.MethodToRun = testMethod.ToRuntimeMethod(); } var passedArguments = Reflector.ConvertArguments( dataRow, this.MethodToRun.GetParameters().Select(p => p.ParameterType).ToArray()); var generatedArguments = GetGeneratedArguments( typeParameters, typeArguments, parameters, passedArguments.Length); var arguments = passedArguments .Select(value => new Argument(value)) .Concat(generatedArguments) .ToList(); this.ScenarioDisplayName = GetScenarioDisplayName(scenarioOutlineDisplayName, typeArguments, parameters, arguments); this.ConvertedDataRow = arguments.Select(argument => argument.Value).ToList(); }
/// <summary> /// Initializes a new instance of the <see cref="XunitTestCaseRunner"/> class. /// </summary> /// <param name="testCase">The test case to be run.</param> /// <param name="displayName">The display name of the test case.</param> /// <param name="skipReason">The skip reason, if the test is to be skipped.</param> /// <param name="constructorArguments">The arguments to be passed to the test class constructor.</param> /// <param name="testMethodArguments">The arguments to be passed to the test method.</param> /// <param name="messageBus">The message bus to report run status to.</param> /// <param name="aggregator">The exception aggregator used to run code and collect exceptions.</param> /// <param name="cancellationTokenSource">The task cancellation token source, used to cancel the test run.</param> public XunitTestCaseRunner( IXunitTestCase testCase, string displayName, string?skipReason, object?[] constructorArguments, object?[]?testMethodArguments, IMessageBus messageBus, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) : base(testCase, messageBus, aggregator, cancellationTokenSource) { this.displayName = Guard.ArgumentNotNull(nameof(displayName), displayName); this.constructorArguments = Guard.ArgumentNotNull(nameof(constructorArguments), constructorArguments); SkipReason = skipReason; testClass = TestCase.TestMethod.TestClass.Class.ToRuntimeType() ?? throw new ArgumentException("testCase.TestMethod.TestClass.Class does not map to a Type object", nameof(testCase)); testMethod = TestCase.Method.ToRuntimeMethod() ?? throw new ArgumentException("testCase.TestMethod does not map to a MethodInfo object", nameof(testCase)); var parameters = TestMethod.GetParameters(); var parameterTypes = new Type[parameters.Length]; for (var i = 0; i < parameters.Length; i++) { parameterTypes[i] = parameters[i].ParameterType; } TestMethodArguments = Reflector.ConvertArguments(testMethodArguments, parameterTypes); }
public void ConvertsStringToGuid(string text) { var guid = Guid.Parse(text); var args = Reflector.ConvertArguments(new object[] { text }, new[] { typeof(Guid) }); Assert.Equal(guid, Assert.IsType <Guid>(args[0])); }
public void ConvertsStringToDateTimeOffset(string text) { var dateTimeOffset = DateTimeOffset.Parse(text, CultureInfo.InvariantCulture); var args = Reflector.ConvertArguments(new object[] { text }, new[] { typeof(DateTimeOffset) }); Assert.Equal(dateTimeOffset, Assert.IsType <DateTimeOffset>(args[0])); }
static string[] GetCultures(IAttributeInfo culturedTheoryAttribute) { var ctorArgs = culturedTheoryAttribute.GetConstructorArguments().ToArray(); var cultures = Reflector.ConvertArguments(ctorArgs, new[] { typeof(string[]) }).Cast <string[]>().Single(); if (cultures == null || cultures.Length == 0) { cultures = new[] { "en-US", "fr-FR" }; } return(cultures); }
protected override async Task AfterTestCaseStartingAsync() { await base.AfterTestCaseStartingAsync(); try { var dataAttributes = TestCase.TestMethod.Method.GetCustomAttributes(typeof(DataAttribute)); foreach (var dataAttribute in dataAttributes) { var discovererAttribute = dataAttribute.GetCustomAttributes(typeof(DataDiscovererAttribute)).First(); var args = discovererAttribute.GetConstructorArguments().Cast <string>().ToList(); var discovererType = SerializationHelper.GetType(args[1], args[0]); var discoverer = ExtensibilityPointFactory.GetDataDiscoverer(_diagnosticMessageSink, discovererType); foreach (var dataRow in discoverer.GetData(dataAttribute, TestCase.TestMethod.Method)) { _toDispose.AddRange(dataRow.OfType <IDisposable>()); ITypeInfo[] resolvedTypes = null; var methodToRun = TestMethod; if (methodToRun.IsGenericMethodDefinition) { resolvedTypes = TestCase.TestMethod.Method.ResolveGenericTypes(dataRow); methodToRun = methodToRun.MakeGenericMethod(resolvedTypes.Select(t => ((IReflectionTypeInfo)t).Type).ToArray()); } var parameterTypes = methodToRun.GetParameters().Select(p => p.ParameterType).ToArray(); var convertedDataRow = Reflector.ConvertArguments(dataRow, parameterTypes); string theoryDisplayName; if (convertedDataRow.Length == 1 && convertedDataRow[0] is Test.IReadableTestCase) { theoryDisplayName = ((Test.IReadableTestCase)convertedDataRow[0]).TestCase(); } else { theoryDisplayName = TestCase.TestMethod.Method.GetDisplayNameWithArguments(DisplayName, convertedDataRow, resolvedTypes); } var test = new XunitTest(TestCase, theoryDisplayName); var skipReason = SkipReason ?? dataAttribute.GetNamedArgument <string>("Skip"); _testRunners.Add(new XunitTestRunner(test, MessageBus, TestClass, ConstructorArguments, methodToRun, convertedDataRow, skipReason, BeforeAfterAttributes, Aggregator, CancellationTokenSource)); } } } catch (Exception ex) { // Stash the exception so we can surface it during RunTestAsync _dataDiscoveryException = ex; } }
public static async Task InvokeAsync(this MethodInfo method, object obj, object[] arguments) { method = method ?? throw new ArgumentNullException(nameof(method)); var parameterTypes = method.GetParameters().Select(parameter => parameter.ParameterType).ToArray(); Reflector.ConvertArguments(arguments, parameterTypes); if (method.Invoke(obj, arguments) is Task task) { await task; } }
public static async Task InvokeAsync(this MethodInfo method, object obj, object[] arguments) { Guard.AgainstNullArgument(nameof(method), method); var parameterTypes = method.GetParameters().Select(parameter => parameter.ParameterType).ToArray(); Reflector.ConvertArguments(arguments, parameterTypes); if (method.Invoke(obj, arguments) is Task task) { await task; } }
public IEnumerable <IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) { var ctorArgs = factAttribute.GetConstructorArguments().ToArray(); var cultures = Reflector.ConvertArguments(ctorArgs, new[] { typeof(string[]) }).Cast <string[]>().Single(); if (cultures == null || cultures.Length == 0) { cultures = new[] { "en-US", "fr-FR" } } ; return(cultures.Select(culture => new CulturedXunitTestCase(diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod, culture)).ToList()); } }
public ScenarioRunner Create(object[] scenarioMethodArguments) { var parameters = this.scenarioOutlineMethod.GetParameters().ToArray(); var typeParameters = this.scenarioOutlineMethod.GetGenericArguments().ToArray(); ITypeInfo[] typeArguments; MethodInfo scenarioMethod; if (this.scenarioOutlineMethod.IsGenericMethodDefinition) { typeArguments = typeParameters .Select(typeParameter => InferTypeArgument(typeParameter.Name, parameters, scenarioMethodArguments)) .ToArray(); scenarioMethod = this.scenarioOutlineMethod.MakeGenericMethod(typeArguments.ToArray()).ToRuntimeMethod(); } else { typeArguments = new ITypeInfo[0]; scenarioMethod = this.scenarioOutlineMethod.ToRuntimeMethod(); } var passedArguments = Reflector.ConvertArguments( scenarioMethodArguments, scenarioMethod.GetParameters().Select(p => p.ParameterType).ToArray()); var generatedArguments = GetGeneratedArguments( typeParameters, typeArguments, parameters, passedArguments.Length); var arguments = passedArguments .Select(value => new Argument(value)) .Concat(generatedArguments) .ToArray(); var scenarioDisplayName = GetScenarioDisplayName( this.scenarioOutlineDisplayName, typeArguments, parameters, arguments); var scenario = new Scenario(this.scenarioOutline, scenarioDisplayName); return(new ScenarioRunner( scenario, this.messageBus, this.scenarioClass, this.constructorArguments, scenarioMethod, arguments.Select(argument => argument.Value).ToArray(), this.skipReason, this.beforeAfterScenarioAttributes, new ExceptionAggregator(this.aggregator), this.cancellationTokenSource)); }
public IEnumerable <IXunitTestCase> Discover(ITestCollection testCollection, IAssemblyInfo assembly, ITypeInfo testClass, IMethodInfo testMethod, IAttributeInfo factAttribute) { var ctorArgs = factAttribute.GetConstructorArguments().ToArray(); var cultures = Reflector.ConvertArguments(ctorArgs, new[] { typeof(string[]) }).Cast <string[]>().Single(); if (cultures == null || cultures.Length == 0) { cultures = new[] { "en-US", "fr-FR" } } ; return(cultures.Select(culture => new CulturedXunitTestCase(testCollection, assembly, testClass, testMethod, factAttribute, culture)).ToList()); } }
/// <summary> /// /// </summary> /// <param name="testCase"></param> /// <param name="displayName"></param> /// <param name="skipReason"></param> /// <param name="constructorArguments"></param> /// <param name="testMethodArguments"></param> /// <param name="messageBus"></param> /// <param name="aggregator"></param> /// <param name="cancellationTokenSource"></param> public ScenarioTestCaseRunner(IXunitTestCase testCase, string displayName, string skipReason, object[] constructorArguments, object[] testMethodArguments, IMessageBus messageBus, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) : base(testCase, displayName, skipReason, constructorArguments, testMethodArguments, messageBus, aggregator, cancellationTokenSource) { DisplayName = displayName; SkipReason = skipReason; ConstructorArguments = constructorArguments; TestClass = base.TestCase.TestMethod.TestClass.Class.ToRuntimeType(); TestMethod = base.TestCase.Method.ToRuntimeMethod(); ParameterInfo[] parameters = TestMethod.GetParameters(); Type[] parameterTypes = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { parameterTypes[i] = parameters[i].ParameterType; } TestMethodArguments = Reflector.ConvertArguments(testMethodArguments, parameterTypes); }
private void CreateTheorySpecificTestRunners() { try { var dataAttributes = TestCase.TestMethod.Method.GetCustomAttributes(typeof(DataAttribute)); foreach (var dataAttribute in dataAttributes) { var discovererAttribute = dataAttribute.GetCustomAttributes(typeof(DataDiscovererAttribute)).First(); var args = discovererAttribute.GetConstructorArguments().Cast <string>().ToList(); var discovererType = LoadType(args[1], args[0]); var discoverer = ExtensibilityPointFactory.GetDataDiscoverer(_diagnosticMessageSink, discovererType); foreach (var dataRow in discoverer.GetData(dataAttribute, TestCase.TestMethod.Method)) { _toDispose.AddRange(dataRow.OfType <IDisposable>()); ITypeInfo[] resolvedTypes = null; var methodToRun = TestMethod; if (methodToRun.IsGenericMethodDefinition) { resolvedTypes = TestCase.TestMethod.Method.ResolveGenericTypes(dataRow); methodToRun = methodToRun.MakeGenericMethod(resolvedTypes.Select(t => ((IReflectionTypeInfo)t).Type).ToArray()); } var parameterTypes = methodToRun.GetParameters().Select(p => p.ParameterType).ToArray(); var convertedDataRow = Reflector.ConvertArguments(dataRow, parameterTypes); var theoryDisplayName = TestCase.TestMethod.Method.GetDisplayNameWithArguments(DisplayName, convertedDataRow, resolvedTypes); var test = new XunitTest(TestCase, theoryDisplayName); _testRunners.Add(new ScenarioTestRunner(test, MessageBus, TestClass, ConstructorArguments, methodToRun, convertedDataRow, SkipReason, BeforeAfterAttributes, Aggregator, CancellationTokenSource)); } } } catch (Exception ex) { // Stash the exception so we can surface it during RunTestAsync _dataDiscoveryException = ex; } }
public ScenarioInfo(IMethodInfo testMethod, object[] actualArgs, string scenarioOutlineDisplayName) { //Guard.AgainstNullArgument(nameof(testMethod), testMethod); #if DEBUG testMethod = testMethod.RequiresNotNull(nameof(testMethod)); #endif // Which, we "do", in DEBUG mode. #pragma warning disable CA1062 // ...validate parameter 'name' is non-null before using it... var parameters = testMethod.GetParameters().ToList(); #pragma warning restore CA1062 // ...validate parameter 'name' is non-null before using it... var typeParams = testMethod.GetGenericArguments().ToList(); ITypeInfo[] typeArgs; if (testMethod.IsGenericMethodDefinition) { typeArgs = typeParams .Select(typeParameter => InferTypeArgument(typeParameter.Name, parameters, actualArgs)) .ToArray(); this.MethodToRun = testMethod.MakeGenericMethod(typeArgs).ToRuntimeMethod(); } else { typeArgs = Array.Empty <ITypeInfo>(); this.MethodToRun = testMethod.ToRuntimeMethod(); } var passedArgs = Reflector.ConvertArguments(actualArgs, this.MethodToRun.GetParameters().Select(p => p.ParameterType).ToArray()); var generatedArguments = GetGeneratedArguments(typeParams, typeArgs, parameters, passedArgs.Length); var args = passedArgs .Select(value => new Argument(value)) .Concat(generatedArguments) .ToList(); this.ScenarioDisplayName = GetScenarioDisplayName(scenarioOutlineDisplayName, typeArgs, parameters, args); this.ConvertedActualArgs = args.Select(arg => arg.Value).ToList(); }
/// <summary> /// Computes values from the test case and resolves the test method arguments. To be called by the public RunAsync method that /// will end up being exposed by the derived class as the primary public API. /// </summary> /// <param name="testCase">The test case that is being run</param> /// <param name="testMethodArguments">The test method arguments to be converted</param> protected (Type TestClass, MethodInfo TestMethod, IReadOnlyCollection <BeforeAfterTestAttribute> BeforeAfterTestAttributes) Initialize( IXunitTestCase testCase, ref object?[]?testMethodArguments) { // TODO: This means XunitTestFramework can never run test cases without a class & method var testClass = testCase.TestClass?.Class.ToRuntimeType() ?? throw new ArgumentException("testCase.TestClass.Class does not map to a Type object", nameof(testCase)); var testMethod = testCase.Method.ToRuntimeMethod() ?? throw new ArgumentException("testCase.TestMethod does not map to a MethodInfo object", nameof(testCase)); var parameters = testMethod.GetParameters(); var parameterTypes = new Type[parameters.Length]; for (var i = 0; i < parameters.Length; i++) { parameterTypes[i] = parameters[i].ParameterType; } testMethodArguments = Reflector.ConvertArguments(testMethodArguments, parameterTypes); IEnumerable <Attribute> beforeAfterTestCollectionAttributes; if (testCase.TestCollection.CollectionDefinition is _IReflectionTypeInfo collectionDefinition) { beforeAfterTestCollectionAttributes = collectionDefinition.Type.GetCustomAttributes(typeof(BeforeAfterTestAttribute)); } else { beforeAfterTestCollectionAttributes = Enumerable.Empty <Attribute>(); } var beforeAfterTestAttributes = beforeAfterTestCollectionAttributes .Concat(testClass.GetCustomAttributes(typeof(BeforeAfterTestAttribute))) .Concat(testMethod.GetCustomAttributes(typeof(BeforeAfterTestAttribute))) .Concat(testClass.Assembly.GetCustomAttributes(typeof(BeforeAfterTestAttribute))) .Cast <BeforeAfterTestAttribute>() .CastOrToReadOnlyCollection(); return(testClass, testMethod, beforeAfterTestAttributes); }
public ValueTask <IReadOnlyCollection <IXunitTestCase> > Discover( _ITestFrameworkDiscoveryOptions discoveryOptions, _ITestMethod testMethod, _IAttributeInfo factAttribute) { var ctorArgs = factAttribute.GetConstructorArguments().ToArray(); var cultures = Reflector.ConvertArguments(ctorArgs, new[] { typeof(string[]) }).Cast <string[]>().Single(); if (cultures == null || cultures.Length == 0) { cultures = new[] { "en-US", "fr-FR" } } ; var methodDisplay = discoveryOptions.MethodDisplayOrDefault(); var methodDisplayOptions = discoveryOptions.MethodDisplayOptionsOrDefault(); var result = cultures .Select(culture => CreateTestCase(testMethod, culture, methodDisplay, methodDisplayOptions)) .CastOrToReadOnlyCollection(); return(new(result)); } CulturedXunitTestCase CreateTestCase( _ITestMethod testMethod, string culture, TestMethodDisplay methodDisplay, TestMethodDisplayOptions methodDisplayOptions) { return(new CulturedXunitTestCase( methodDisplay, methodDisplayOptions, testMethod, culture )); } }
private async Task ExecuteTestMethod(MethodInfo runtimeMethod, RunSummary runSummary, IEnumerable <WebDriverAttribute> driverAttributes, object[] dataRow) { foreach (var driverAttribute in driverAttributes) { foreach (var driver in driverAttribute.GetDrivers(runtimeMethod)) { Fixture newFixture = null; object initializerReturn = null; ITypeInfo[] resolvedTypes = null; var methodToRun = runtimeMethod; if (methodToRun.IsGenericMethodDefinition) { resolvedTypes = TestCase.TestMethod.Method.ResolveGenericTypes(dataRow); methodToRun = methodToRun.MakeGenericMethod(resolvedTypes.Select(t => ((IReflectionTypeInfo)t).Type).ToArray()); } List <object> parameterList = new List <object>(); var parameters = methodToRun.GetParameters().ToArray(); try { newFixture = FixtureCreationAttribute.GetNewFixture(driver, runtimeMethod); var initializeDataAttributes = ReflectionHelper.GetAttributes <FixtureInitializationAttribute>(runtimeMethod); foreach (var initializeDataAttribute in initializeDataAttributes) { if (initializeDataAttribute is IMethodInfoAware) { #if DNX var property = initializeDataAttribute.GetType().GetRuntimeProperty("Method"); property.SetValue(initializeDataAttribute, runtimeMethod); #else ((IMethodInfoAware)initializeDataAttribute).Method = runtimeMethod; #endif } initializeDataAttribute.Initialize(newFixture.Data); } var initializeAttribute = ReflectionHelper.GetAttribute <IFixtureInitializationAttribute>(runtimeMethod); if (initializeAttribute != null) { initializerReturn = initializeAttribute.Initialize(runtimeMethod, newFixture); } int dataRowIndex = 0; for (int i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; var attributes = parameter.GetCustomAttributes(true); if (parameter.ParameterType == typeof(IWebDriver)) { parameterList.Add(driver); } else if (parameter.ParameterType == typeof(Fixture)) { parameterList.Add(newFixture); } else if (attributes.Any(a => a is GenerateAttribute)) { var generateAttribute = (GenerateAttribute)attributes.First(a => a is GenerateAttribute); InitializeCustomAttribute(generateAttribute, runtimeMethod, parameter); var constraintName = generateAttribute.ConstraintName ?? parameter.Name; var min = generateAttribute.Min; var max = generateAttribute.Max; var value = newFixture.Data.Generate(parameter.ParameterType, constraintName, new { min, max }); parameterList.Add(value); } else if (attributes.Any(a => a is LocateAttribute)) { var locateAttribute = (LocateAttribute)attributes.First(a => a is LocateAttribute); InitializeCustomAttribute(locateAttribute, runtimeMethod, parameter); var value = locateAttribute.Value; if (value == null) { value = newFixture.Data.Generate(new SimpleFixture.DataRequest(null, newFixture.Data, parameter.ParameterType, parameter.Name, false, null, null)); } parameterList.Add(value); } else if (attributes.Any(a => a is FreezeAttribute)) { var freeze = (FreezeAttribute)attributes.FirstOrDefault(a => a is FreezeAttribute); InitializeCustomAttribute(freeze, runtimeMethod, parameter); var value = freeze.Value; if (value == null) { var constraintName = freeze.ConstraintName ?? parameter.Name; var min = freeze.Min; var max = freeze.Max; value = newFixture.Data.Generate(parameter.ParameterType, constraintName, new { min, max }); } parameterList.Add(value); object lastObject = parameterList.Last(); var closedFreezeMethod = FreezeMethod.MakeGenericMethod(lastObject.GetType()); closedFreezeMethod.Invoke(null, new object[] { newFixture.Data, value, freeze.For }); } else if (initializerReturn != null && parameter.ParameterType == initializerReturn.GetType()) { parameterList.Add(initializerReturn); initializerReturn = null; } else if (dataRowIndex < dataRow.Length) { var dataValue = dataRow[dataRowIndex]; dataRowIndex++; parameterList.Add(dataValue); } else { var value = newFixture.Data.Generate(parameter.ParameterType, parameter.Name); parameterList.Add(value); } } } catch (Exception exp) { Aggregator.Add(exp); } var convertedDataRow = Reflector.ConvertArguments(parameterList.ToArray(), parameters.Select(p => p.ParameterType).ToArray()); var theoryDisplayName = TestCase.TestMethod.Method.GetDisplayNameWithArguments(DisplayName + " " + GetDriverName(driver), dataRow, resolvedTypes); var test = new XunitTest(TestCase, theoryDisplayName); var skipReason = SkipReason; XunitTestRunner testRunner = CreateTestRunner(test, MessageBus, TestClass, ConstructorArguments, methodToRun, convertedDataRow, skipReason, BeforeAfterAttributes, Aggregator, CancellationTokenSource); runSummary.Aggregate(await testRunner.RunAsync()); var timer = new ExecutionTimer(); timer.Aggregate(() => DisposeOfData(driverAttribute, driver, newFixture, dataRow)); runSummary.Time += timer.Total; } } }
/// <summary> /// Initializes a new instance of the <see cref="MettleTestCaseRunner"/> class. /// </summary> /// <param name="testCase">The test case to be run.</param> /// <param name="displayName">The display name of the test case.</param> /// <param name="skipReason">The skip reason, if the test is to be skipped.</param> /// <param name="constructorArguments">The arguments to be passed to the test class constructor.</param> /// <param name="testMethodArguments">The arguments to be passed to the test method.</param> /// <param name="messageBus">The message bus to report run status to.</param> /// <param name="aggregator">The exception aggregator used to run code and collect exceptions.</param> /// <param name="cancellationTokenSource">The task cancellation token source, used to cancel the test run.</param> public MettleTestCaseRunner(IXunitTestCase testCase, string displayName, string skipReason, object[] constructorArguments, object[] testMethodArguments, IMessageBus messageBus, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, IServiceProvider serviceProvider) : base(testCase, messageBus, aggregator, cancellationTokenSource) { DisplayName = displayName; SkipReason = skipReason; TestClass = TestCase.TestMethod.TestClass.Class.ToRuntimeType(); TestMethod = TestCase.Method.ToRuntimeMethod(); this.serviceProvider = serviceProvider; var ctor = TestClass.GetConstructors().FirstOrDefault(); var parameters = ctor.GetParameters(); Type[] parameterTypes; object[] args; if (constructorArguments != null || constructorArguments.Length > 0) { parameterTypes = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { parameterTypes[i] = parameters[i].ParameterType; } args = constructorArguments ?? Array.Empty <object>(); var ctorArgs = new object[parameters.Length]; Array.Copy(args, ctorArgs, args.Length); for (int i = 0; i < parameters.Length; i++) { var obj = ctorArgs[i]; if (obj == null) { obj = this.serviceProvider?.GetService(parameters[i].ParameterType); } ctorArgs[i] = obj; } ConstructorArguments = Reflector.ConvertArguments(ctorArgs, parameterTypes); } else { ConstructorArguments = constructorArguments; } parameters = TestMethod.GetParameters(); parameterTypes = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { parameterTypes[i] = parameters[i].ParameterType; } args = testMethodArguments ?? Array.Empty <object>(); if (parameters.Length != args.Length) { var methodArgs = new object[parameters.Length]; Array.Copy(args, methodArgs, args.Length); for (var i = 0; i < parameters.Length; i++) { var obj = methodArgs[i]; if (obj == null) { obj = this.serviceProvider?.GetService(parameters[i].ParameterType); } methodArgs[i] = obj; } args = methodArgs; } TestMethodArguments = Reflector.ConvertArguments(args, parameterTypes); }
protected override async Task AfterTestCaseStartingAsync() { await base.AfterTestCaseStartingAsync(); try { var dataAttributes = TestCase.TestMethod.Method.GetCustomAttributes(typeof(DataAttribute)); foreach (var dataAttribute in dataAttributes) { var discovererAttribute = dataAttribute.GetCustomAttributes(typeof(DataDiscovererAttribute)).First(); var args = discovererAttribute.GetConstructorArguments().Cast <string>().ToList(); var discovererType = LoadType(args[1], args[0]); if (discovererType == null) { if (dataAttribute is IReflectionAttributeInfo reflectionAttribute) { Aggregator.Add(new InvalidOperationException($"Data discoverer specified for {reflectionAttribute.Attribute.GetType()} on {TestCase.TestMethod.TestClass.Class.Name}.{TestCase.TestMethod.Method.Name} does not exist.")); } else { Aggregator.Add(new InvalidOperationException($"A data discoverer specified on {TestCase.TestMethod.TestClass.Class.Name}.{TestCase.TestMethod.Method.Name} does not exist.")); } continue; } IDataDiscoverer discoverer; try { discoverer = ExtensibilityPointFactory.GetDataDiscoverer(_diagnosticMessageSink, discovererType); } catch (InvalidCastException) { if (dataAttribute is IReflectionAttributeInfo reflectionAttribute) { Aggregator.Add(new InvalidOperationException($"Data discoverer specified for {reflectionAttribute.Attribute.GetType()} on {TestCase.TestMethod.TestClass.Class.Name}.{TestCase.TestMethod.Method.Name} does not implement IDataDiscoverer.")); } else { Aggregator.Add(new InvalidOperationException($"A data discoverer specified on {TestCase.TestMethod.TestClass.Class.Name}.{TestCase.TestMethod.Method.Name} does not implement IDataDiscoverer.")); } continue; } var data = discoverer.GetData(dataAttribute, TestCase.TestMethod.Method); if (data == null) { Aggregator.Add(new InvalidOperationException($"Test data returned null for {TestCase.TestMethod.TestClass.Class.Name}.{TestCase.TestMethod.Method.Name}. Make sure it is statically initialized before this test method is called.")); continue; } foreach (var dataRow in data) { _toDispose.AddRange(dataRow.OfType <IDisposable>()); ITypeInfo[] resolvedTypes = null; var methodToRun = TestMethod; var convertedDataRow = methodToRun.ResolveMethodArguments(dataRow); if (methodToRun.IsGenericMethodDefinition) { resolvedTypes = TestCase.TestMethod.Method.ResolveGenericTypes(convertedDataRow); methodToRun = methodToRun.MakeGenericMethod(resolvedTypes.Select(t => ((IReflectionTypeInfo)t).Type).ToArray()); } var parameterTypes = methodToRun.GetParameters().Select(p => p.ParameterType).ToArray(); convertedDataRow = Reflector.ConvertArguments(convertedDataRow, parameterTypes); var theoryDisplayName = TestCase.TestMethod.Method.GetDisplayNameWithArguments(DisplayName, convertedDataRow, resolvedTypes); var test = CreateTest(TestCase, theoryDisplayName); var skipReason = SkipReason ?? dataAttribute.GetNamedArgument <string>("Skip"); _testRunners.Add(new ScenarioTestRunner(test, MessageBus, TestClass, ConstructorArguments, methodToRun, convertedDataRow, skipReason, BeforeAfterAttributes, new ExceptionAggregator(Aggregator), CancellationTokenSource)); } } } catch (Exception ex) { // Stash the exception so we can surface it during RunTestAsync _dataDiscoveryException = ex; } }
private async Task ExecuteTestMethod(MethodInfo runtimeMethod, RunSummary runSummary, IEnumerable <IApplicationAttribute> applicationAttributes, object[] dataRow) { foreach (var applicationAttribute in applicationAttributes) { Application application = null; Window mainWindow = null; WindowFixture fixture = null; try { application = applicationAttribute.ProvideApplication(runtimeMethod); application.WaitWhileBusy(); mainWindow = null; if (!string.IsNullOrEmpty(applicationAttribute.Window)) { mainWindow = application.GetWindow(applicationAttribute.Window); } else { mainWindow = application.GetWindows().FirstOrDefault(); } if (mainWindow == null) { throw new Exception("Could not locate main window " + applicationAttribute.Window); } fixture = new WindowFixture(application, mainWindow); ITypeInfo[] resolvedTypes = null; var methodToRun = runtimeMethod; if (methodToRun.IsGenericMethodDefinition) { resolvedTypes = TestCase.TestMethod.Method.ResolveGenericTypes(dataRow); methodToRun = methodToRun.MakeGenericMethod(resolvedTypes.Select(t => ((IReflectionTypeInfo)t).Type).ToArray()); } List <object> parameterList = new List <object>(); var parameters = methodToRun.GetParameters().ToArray(); object initializerReturn = null; int dataRowIndex = 0; for (int i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; var attributes = parameter.GetCustomAttributes(true); if (parameter.ParameterType == typeof(Window)) { parameterList.Add(mainWindow); } else if (parameter.ParameterType == typeof(IWindowFixture)) { parameterList.Add(fixture); } else if (attributes.Any(a => a is GenerateAttribute)) { var generateAttribute = (GenerateAttribute)attributes.First(a => a is GenerateAttribute); InitializeCustomAttribute(generateAttribute, runtimeMethod, parameter); var constraintName = generateAttribute.ConstraintName ?? parameter.Name; var min = generateAttribute.Min; var max = generateAttribute.Max; var value = fixture.Data.Generate(parameter.ParameterType, constraintName, new { min, max }); parameterList.Add(value); } else if (attributes.Any(a => a is LocateAttribute)) { var locateAttribute = (LocateAttribute)attributes.First(a => a is LocateAttribute); InitializeCustomAttribute(locateAttribute, runtimeMethod, parameter); var value = locateAttribute.Value; if (value == null) { value = fixture.Data.Generate(new SimpleFixture.DataRequest(null, fixture.Data, parameter.ParameterType, parameter.Name, false, null, null)); } parameterList.Add(value); } else if (attributes.Any(a => a is FreezeAttribute)) { var freeze = (FreezeAttribute)attributes.FirstOrDefault(a => a is FreezeAttribute); InitializeCustomAttribute(freeze, runtimeMethod, parameter); var value = freeze.Value; if (value == null) { var constraintName = freeze.ConstraintName ?? parameter.Name; var min = freeze.Min; var max = freeze.Max; value = fixture.Data.Generate(parameter.ParameterType, constraintName, new { min, max }); } parameterList.Add(value); object lastObject = parameterList.Last(); var closedFreezeMethod = FreezeMethod.MakeGenericMethod(lastObject.GetType()); closedFreezeMethod.Invoke(null, new object[] { fixture.Data, value, freeze.For }); } else if (initializerReturn != null && parameter.ParameterType == initializerReturn.GetType()) { parameterList.Add(initializerReturn); initializerReturn = null; } else if (dataRowIndex < dataRow.Length) { var dataValue = dataRow[dataRowIndex]; dataRowIndex++; parameterList.Add(dataValue); } else { var value = fixture.Data.Generate(parameter.ParameterType, parameter.Name); parameterList.Add(value); } } var convertedDataRow = Reflector.ConvertArguments(parameterList.ToArray(), parameters.Select(p => p.ParameterType).ToArray()); var theoryDisplayName = TestCase.TestMethod.Method.GetDisplayNameWithArguments(DisplayName + " " + applicationAttribute.Application, dataRow, resolvedTypes); var test = new XunitTest(TestCase, theoryDisplayName); var skipReason = SkipReason; XunitTestRunner testRunner = CreateTestRunner(test, MessageBus, TestClass, ConstructorArguments, methodToRun, convertedDataRow, skipReason, BeforeAfterAttributes, Aggregator, CancellationTokenSource); runSummary.Aggregate(await testRunner.RunAsync()); } catch (Exception exp) { Aggregator.Add(exp); } finally { var timer = new ExecutionTimer(); timer.Aggregate(() => DisposeOfData(application, mainWindow, fixture, dataRow)); runSummary.Time += timer.Total; } } }
private async Task <RunSummary> InvokeScenarioMethodAsync(object scenarioClassInstance) { var backgroundSteps = new List <IStepDefinition>(); var scenarioSteps = new List <IStepDefinition>(); var tearDownSteps = new List <IStepDefinition>(); await this._aggregator.RunAsync(async() => { // We leverage this for both Background and TearDown methods. async Task OnDiscoverSupportMethodsAsync <TAttribute>( IScenario scenario, ExecutionTimer timer) where TAttribute : SupportMethodAttribute { var methods = scenario.TestCase.TestMethod.TestClass.Class .GetMethods(false) .Where(candidate => candidate.GetCustomAttributes(typeof(TAttribute)).Any()) .Select(method => method.ToRuntimeMethod()) // #2 MWP 2020-07-01 12:28:03 PM: the rubber meeting the road here. .OrderBy(method => method, new MethodInfoComparer()).ToList(); // Thus ensuring correct front to back Background, reverse TearDown. if (typeof(TAttribute) == typeof(TearDownAttribute)) { methods.Reverse(); } foreach (var method in methods) { /* #4 MWP 2020-07-09 05:47:25 PM / We support seeding default values into * Background methods with parameters. However, this is the extent of what * we can accomplish there. It does not make any sense to cross any Theory * dataRow bridges for Background methods. */ var argTypes = method.GetParameters().Select(param => param.ParameterType).ToArray(); var args = argTypes.Select(paramType => paramType.GetDefault()).ToArray(); var convertedArgs = Reflector.ConvertArguments(args, argTypes); convertedArgs = convertedArgs.Any() ? convertedArgs : null; await timer.AggregateAsync(() => method.InvokeAsync(scenarioClassInstance, convertedArgs)); } } using (CurrentThread.EnterStepDefinitionContext()) { await OnDiscoverSupportMethodsAsync <BackgroundAttribute>(this._scenario, this._timer); backgroundSteps.AddRange(CurrentThread.StepDefinitions); } using (CurrentThread.EnterStepDefinitionContext()) { await this._timer.AggregateAsync(() => this._scenarioMethod.InvokeAsync(scenarioClassInstance, this._scenarioMethodArguments)); scenarioSteps.AddRange(CurrentThread.StepDefinitions); } // MWP Sun, 06 Dec 2020 11:00:56 AM / Rinse and repeat Background, except for TearDown... using (CurrentThread.EnterStepDefinitionContext()) { await OnDiscoverSupportMethodsAsync <TearDownAttribute>(this._scenario, this._timer); tearDownSteps.AddRange(CurrentThread.StepDefinitions); } }); var runSummary = new RunSummary { Time = this._timer.Total }; if (!this._aggregator.HasExceptions) { // Assumes Scenario for StepDefinitionType. backgroundSteps.ForEach(x => x.StepDefinitionType = StepType.Background); tearDownSteps.ForEach(x => x.StepDefinitionType = StepType.TearDown); runSummary.Aggregate(await this.InvokeStepsAsync(backgroundSteps, scenarioSteps, tearDownSteps)); } return(runSummary); }