diff --git a/src/TestStack.BDDfy.Tests/AssemblyInfo.cs b/src/TestStack.BDDfy.Tests/AssemblyInfo.cs new file mode 100644 index 0000000..75812dc --- /dev/null +++ b/src/TestStack.BDDfy.Tests/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/src/TestStack.BDDfy.Tests/Exceptions/ExceptionThrowingTest.cs b/src/TestStack.BDDfy.Tests/Exceptions/ExceptionThrowingTest.cs index a9fb85a..05325e3 100644 --- a/src/TestStack.BDDfy.Tests/Exceptions/ExceptionThrowingTest.cs +++ b/src/TestStack.BDDfy.Tests/Exceptions/ExceptionThrowingTest.cs @@ -6,9 +6,9 @@ namespace TestStack.BDDfy.Tests.Exceptions { public class ExceptionThrowingTest where T : Exception, new() { - private static bool _givenShouldThrow; - private static bool _whenShouldThrow; - private static bool _thenShouldThrow; + private bool _givenShouldThrow; + private bool _whenShouldThrow; + private bool _thenShouldThrow; Scenario _scenario; void Given() diff --git a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenGivenThrowsException.cs b/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenGivenThrowsException.cs index e34a520..92ccaa5 100644 --- a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenGivenThrowsException.cs +++ b/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenGivenThrowsException.cs @@ -13,6 +13,7 @@ private void ExecuteUsingReflectingScanners() private void ExecuteUsingFluentScanners() { + Should.Throw(() => Sut.Execute(ThrowingMethods.Given, true)); } diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/StepTitleTests.cs b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/StepTitleTests.cs index e566bee..f5276a0 100644 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/StepTitleTests.cs +++ b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/StepTitleTests.cs @@ -1,11 +1,18 @@ -using System.Linq; +using System; +using System.Linq; + using Shouldly; +using TestStack.BDDfy.Configuration; using Xunit; namespace TestStack.BDDfy.Tests.Scanner.FluentScanner { - public class StepTitleTests + public class StepTitleTests:IDisposable { + public StepTitleTests() + { + Configurator.Scanners.SetDefaultStepTitleCreatorFunction(null); + } private string _mutatedState; [Fact] @@ -29,6 +36,113 @@ public void MethodCallInStepTitle() story.Scenarios.Single().Steps.ElementAt(6).Title.ShouldBe("And with foo arg"); } + [Fact] + public void TitleFunctionCanBeOverriden() + { + FooClass something = new FooClass(); + var context = TestContext.GetContext(something); + + Configurator.Scanners.SetDefaultStepTitleCreatorFunction((a, b, c, d, e) => new StepTitle("hello")); + new FluentStepBuilder(something); + var story = something + .Given(_ => GivenWeMutateSomeState()) + .When(_ => something.Sub.SomethingHappens()) + .And(_ => something.Sub.SomethingWithDifferentTitle()) + .Then(_ => ThenTitleHas(AMethodCall())) + .And(_ => something.Sub.SomethingWithArg("foo")) + .And(_ => something.Sub.SomethingWithArg2("foo")) + .And(_ => something.Sub.SomethingWithArg3("foo")) + .BDDfy(); + + story.Scenarios.Single().Steps.ElementAt(2).Title.ShouldBe("hello"); + story.Scenarios.Single().Steps.ElementAt(3).Title.ShouldBe("hello"); + story.Scenarios.Single().Steps.ElementAt(4).Title.ShouldBe("hello"); + story.Scenarios.Single().Steps.ElementAt(5).Title.ShouldBe("hello"); + story.Scenarios.Single().Steps.ElementAt(6).Title.ShouldBe("hello"); + } + + [Fact] + public void TitleFunctionCanBeOverridenAndUseParameters() + { + GivenWeMutateSomeState(); + + FooClass something = new FooClass(); + var context = TestContext.GetContext(something); + + Configurator.Scanners.SetDefaultStepTitleCreatorFunction((a, b, c, d, e) => new StepTitle(e + " " + c.Name + " " + string.Join(",", d.Select(arg => arg.Value).ToArray()))); + new FluentStepBuilder(something); + var story = something + .Given(_ => GivenWeMutateSomeState()) + .When(_ => something.Sub.SomethingHappens()) + .And(_ => something.Sub.SomethingWithDifferentTitle()) + .Then(_ => ThenTitleHas(AMethodCall())) + .And(_ => something.Sub.SomethingWithArg("foo")) + .And(_ => something.Sub.SomethingWithArg2("foo2")) + .And(_ => something.Sub.SomethingWithArg3("foo3")) + .BDDfy(); + + story.Scenarios.Single().Steps.ElementAt(0).Title.ShouldBe("Given GivenWeMutateSomeState "); + story.Scenarios.Single().Steps.ElementAt(1).Title.ShouldBe("When SomethingHappens "); + story.Scenarios.Single().Steps.ElementAt(2).Title.ShouldBe("And SomethingWithDifferentTitle "); + story.Scenarios.Single().Steps.ElementAt(3).Title.ShouldBe("Then ThenTitleHas Mutated state"); + story.Scenarios.Single().Steps.ElementAt(4).Title.ShouldBe("And SomethingWithArg foo"); + story.Scenarios.Single().Steps.ElementAt(5).Title.ShouldBe("And SomethingWithArg2 foo2"); + story.Scenarios.Single().Steps.ElementAt(6).Title.ShouldBe("And SomethingWithArg3 foo3"); + } + [Fact] + public void TitleFunctionCanBeOverridenWithinTestAndUseParameters() + { + GivenWeMutateSomeState(); + + FooClass something = new FooClass(); + var context = TestContext.GetContext(something); + Configurator.Scanners.SetDefaultStepTitleCreatorFunction((a, b, c, d, e) => new StepTitle(e + " " + c.Name + " " + string.Join(",", d.Select(arg => arg.Value).ToArray()))); + new FluentStepBuilder(something); + var story = something + .Given(_ => GivenWeMutateSomeState()) + .When(_ => something.Sub.SomethingHappens()) + .And(_ => something.Sub.SomethingWithDifferentTitle()) + .Then(_ => ThenTitleHas(AMethodCall())) + .And(_ => something.Sub.SomethingWithArg("foo")) + .And(_ => something.Sub.SomethingWithArg2("foo2")) + .And(_ => something.Sub.SomethingWithArg3("foo3")) + .BDDfy(); + + story.Scenarios.Single().Steps.ElementAt(0).Title.ShouldBe("Given GivenWeMutateSomeState "); + story.Scenarios.Single().Steps.ElementAt(1).Title.ShouldBe("When SomethingHappens "); + story.Scenarios.Single().Steps.ElementAt(2).Title.ShouldBe("And SomethingWithDifferentTitle "); + story.Scenarios.Single().Steps.ElementAt(3).Title.ShouldBe("Then ThenTitleHas Mutated state"); + story.Scenarios.Single().Steps.ElementAt(4).Title.ShouldBe("And SomethingWithArg foo"); + story.Scenarios.Single().Steps.ElementAt(5).Title.ShouldBe("And SomethingWithArg2 foo2"); + story.Scenarios.Single().Steps.ElementAt(6).Title.ShouldBe("And SomethingWithArg3 foo3"); + } + + [Fact] + public void TitleFunctionCanBeOverridenFromThestartWithinTestAndUseParameters() + { + GivenWeMutateSomeState(); + + FooClass something = new FooClass(); + var context = TestContext.GetContext(something); + new FluentStepBuilder(something); + var story = something + .SetStepTitleFunction((a, b, c, d, e) => new StepTitle("hello")) + .Given(_ => GivenWeMutateSomeState()) + .When(_ => something.Sub.SomethingHappens()) + .BDDfy(); + + story.Scenarios.Single().Steps.ElementAt(0).Title.ShouldBe("hello"); + story.Scenarios.Single().Steps.ElementAt(1).Title.ShouldBe("hello"); + + + var story2 = something + .Given(_ => GivenWeMutateSomeState()) + .BDDfy(); + + story2.Scenarios.Single().Steps.ElementAt(0).Title.ShouldBe("Given we mutate some state"); + + } + public class FooClass { public FooClass() @@ -43,7 +157,6 @@ public class BarClass { public void SomethingHappens() { - } [StepTitle("Different title")] @@ -81,5 +194,11 @@ private void ThenTitleHas(string result) { result.ShouldBe(_mutatedState); } + + public void Dispose() + { + Configurator.Scanners.SetDefaultStepTitleCreatorFunction(null); + + } } } \ No newline at end of file diff --git a/src/TestStack.BDDfy/BDDfyExtensions.cs b/src/TestStack.BDDfy/BDDfyExtensions.cs index 90f69cb..1d161c9 100644 --- a/src/TestStack.BDDfy/BDDfyExtensions.cs +++ b/src/TestStack.BDDfy/BDDfyExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Reflection; using TestStack.BDDfy.Configuration; namespace TestStack.BDDfy @@ -52,7 +53,9 @@ public static Engine LazyBDDfy(this object testObject, string scenarioTi /// public static Story BDDfy(this object testObject, string scenarioTitle = null, [System.Runtime.CompilerServices.CallerMemberName] string caller = null) { - return InternalLazyBDDfy(testObject, scenarioTitle ?? Configurator.Scanners.Humanize(caller)).Run(); + var currentStory= InternalLazyBDDfy(testObject, scenarioTitle ?? Configurator.Scanners.Humanize(caller)).Run(); + Configurator.Scanners.SetCustomStepTitleCreatorFunction(null); + return currentStory; } public static Engine LazyBDDfy(this object testObject, string scenarioTitle = null, [System.Runtime.CompilerServices.CallerMemberName] string caller = null) @@ -71,10 +74,13 @@ public static Engine LazyBDDfy(this object testObject, string scenarioTitle = nu public static Story BDDfy(this object testObject, string scenarioTitle = null, [System.Runtime.CompilerServices.CallerMemberName] string caller = null) where TStory : class { - return InternalLazyBDDfy(testObject, scenarioTitle ?? Configurator.Scanners.Humanize(caller), typeof(TStory)).Run(); + Story currentStory= InternalLazyBDDfy(testObject, scenarioTitle ?? Configurator.Scanners.Humanize(caller), typeof(TStory)).Run(); + Configurator.Scanners.SetCustomStepTitleCreatorFunction(null); + return currentStory; } - public static Engine LazyBDDfy(this object testObject, string scenarioTitle = null, [System.Runtime.CompilerServices.CallerMemberName] string caller = null) + + public static Engine LazyBDDfy(this object testObject, string scenarioTitle = null, [System.Runtime.CompilerServices.CallerMemberName] string caller = null) where TStory : class { return InternalLazyBDDfy(testObject, scenarioTitle ?? Configurator.Scanners.Humanize(caller), typeof(TStory)); @@ -95,6 +101,7 @@ static Engine InternalLazyBDDfy( return new Engine(storyScanner); } + static IScanner GetReflectiveScanner(ITestContext testContext, string scenarioTitle = null, Type explicitStoryType = null) { var stepScanners = Configurator.Scanners.GetStepScanners(testContext).ToArray(); diff --git a/src/TestStack.BDDfy/Configuration/Scanners.cs b/src/TestStack.BDDfy/Configuration/Scanners.cs index acf73f2..b1705bb 100644 --- a/src/TestStack.BDDfy/Configuration/Scanners.cs +++ b/src/TestStack.BDDfy/Configuration/Scanners.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.Reflection; namespace TestStack.BDDfy.Configuration { public class Scanners { + public readonly StepScannerFactory _ = new StepScannerFactory(() => new ExecutableAttributeStepScanner()); private readonly StepScannerFactory _executableAttributeScanner = new StepScannerFactory(() => new ExecutableAttributeStepScanner()); public StepScannerFactory ExecutableAttributeScanner { get { return _executableAttributeScanner; } } @@ -17,6 +19,17 @@ public Scanners Add(Func stepScannerFactory) _addedStepScanners.Add(stepScannerFactory); return this; } + internal Scanners SetCustomStepTitleCreatorFunction( Func customStepTitleCreatorFunction) + { + CustomStepTitleCreatorFunction= customStepTitleCreatorFunction; + return this; + } + + public Scanners SetDefaultStepTitleCreatorFunction(Func defaultStepTitleCreatorFunction) + { + DefaultStepTitleCreatorFunction = defaultStepTitleCreatorFunction; + return this; + } public IEnumerable GetStepScanners(object objectUnderTest) { @@ -36,6 +49,9 @@ public IEnumerable GetStepScanners(object objectUnderTest) public Func StoryMetadataScanner = () => new StoryAttributeMetadataScanner(); + internal Func CustomStepTitleCreatorFunction = null; + internal Func DefaultStepTitleCreatorFunction = null; + public Func Humanize = NetToString.Convert; } } \ No newline at end of file diff --git a/src/TestStack.BDDfy/Processors/TestRunner.cs b/src/TestStack.BDDfy/Processors/TestRunner.cs index af0c267..e4a67c0 100644 --- a/src/TestStack.BDDfy/Processors/TestRunner.cs +++ b/src/TestStack.BDDfy/Processors/TestRunner.cs @@ -1,5 +1,6 @@ namespace TestStack.BDDfy.Processors { + using System; using System.Linq; public class TestRunner : IProcessor @@ -23,17 +24,18 @@ public void Process(Story story) } var stepFailed = false; + foreach (var executionStep in scenario.Steps) { + executionStep.ResetTitle(); if (stepFailed && ShouldExecuteStepWhenPreviousStepFailed(executionStep)) break; - if (executor.ExecuteStep(executionStep) == Result.Passed) + if (executor.ExecuteStep(executionStep) == Result.Passed) continue; - + if (!executionStep.Asserts) break; - stepFailed = true; } } diff --git a/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/FluentApi.cs b/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/FluentApi.cs index 4beb588..ca573d8 100644 --- a/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/FluentApi.cs +++ b/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/FluentApi.cs @@ -1,7 +1,9 @@ using System; using System.Linq.Expressions; +using System.Reflection; using System.Threading.Tasks; - +using TestStack.BDDfy.Configuration; + // ReSharper disable CheckNamespace // This is in BDDfy namespace to make its usage simpler namespace TestStack.BDDfy @@ -9,60 +11,68 @@ namespace TestStack.BDDfy { public static class FluentStepScannerExtensions { + + public static IFluentStepBuilder SetStepTitleFunction(this TScenario testObject, Func customStepTitleCreatorFunction) + where TScenario : class + { + Configurator.Scanners.SetCustomStepTitleCreatorFunction(customStepTitleCreatorFunction); + return new FluentStepBuilder(testObject); + } + public static IFluentStepBuilder Given(this TScenario testObject, Expression> step, string stepTextTemplate) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).Given(step, stepTextTemplate); } - + public static IFluentStepBuilder Given(this TScenario testObject, Expression> step, bool includeInputsInStepTitle) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).Given(step, includeInputsInStepTitle); } - + public static IFluentStepBuilder Given(this TScenario testObject, Expression> step) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).Given(step); } - + public static IFluentStepBuilder Given(this TScenario testObject, Expression> step, string stepTextTemplate) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).Given(step, stepTextTemplate); } - + public static IFluentStepBuilder Given(this TScenario testObject, Expression> step, bool includeInputsInStepTitle) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).Given(step, includeInputsInStepTitle); } - + public static IFluentStepBuilder Given(this TScenario testObject, Expression> step) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).Given(step); } - + public static IFluentStepBuilder Given(this TScenario testObject, Action step, string title) where TScenario : class { return new FluentStepBuilder(testObject).Given(step, title); } - + public static IFluentStepBuilder Given(this TScenario testObject, Func step, string title) where TScenario : class { return new FluentStepBuilder(testObject).Given(step, title); } - + public static IFluentStepBuilder Given(this TScenario testObject, Expression> action) where TScenario : class { return new FluentStepBuilder(testObject).Given(action); } - + public static IFluentStepBuilder Given(this TScenario testObject, string title) where TScenario : class { @@ -70,53 +80,53 @@ public static IFluentStepBuilder Given(this TScenario test } public static IFluentStepBuilder When(this TScenario testObject, Expression> step, string stepTextTemplate) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).When(step, stepTextTemplate); } - + public static IFluentStepBuilder When(this TScenario testObject, Expression> step, bool includeInputsInStepTitle) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).When(step, includeInputsInStepTitle); } - + public static IFluentStepBuilder When(this TScenario testObject, Expression> step) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).When(step); } - + public static IFluentStepBuilder When(this TScenario testObject, Expression> step, string stepTextTemplate) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).When(step, stepTextTemplate); } - + public static IFluentStepBuilder When(this TScenario testObject, Expression> step, bool includeInputsInStepTitle) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).When(step, includeInputsInStepTitle); } - + public static IFluentStepBuilder When(this TScenario testObject, Expression> step) - where TScenario: class + where TScenario : class { return new FluentStepBuilder(testObject).When(step); } - + public static IFluentStepBuilder When(this TScenario testObject, Action step, string title) where TScenario : class { return new FluentStepBuilder(testObject).When(step, title); } - + public static IFluentStepBuilder When(this TScenario testObject, Func step, string title) where TScenario : class { return new FluentStepBuilder(testObject).When(step, title); } - + public static IFluentStepBuilder When(this TScenario testObject, string title) where TScenario : class { @@ -124,10 +134,13 @@ public static IFluentStepBuilder When(this TScenario testO } } - public interface IFluentStepBuilder where TScenario: class + public interface IFluentStepBuilder where TScenario : class { + TScenario TestObject { get; } + IFluentStepBuilder SetStepTitleFunction(Func customStepTitleCreatorFunction); + IFluentStepBuilder Given(Expression> step, string stepTextTemplate); IFluentStepBuilder Given(Expression> step, bool includeInputsInStepTitle); @@ -308,7 +321,7 @@ interface IFluentStepBuilder object TestObject { get; } } - public class FluentStepBuilder : IFluentStepBuilder, IFluentStepBuilder + public class FluentStepBuilder : IFluentStepBuilder, IFluentStepBuilder where TScenario : class { readonly FluentScanner scanner; @@ -319,8 +332,8 @@ public FluentStepBuilder(TScenario testObject) var existingContext = TestContext.GetContext(TestObject); if (existingContext.FluentScanner == null) existingContext.FluentScanner = new FluentScanner(testObject); - - scanner = (FluentScanner) existingContext.FluentScanner; + existingContext.FluentScanner.SetTitleFunction(); + scanner = (FluentScanner)existingContext.FluentScanner; } public TScenario TestObject { get; private set; } @@ -681,5 +694,11 @@ public IFluentStepBuilder TearDownWith(string title) scanner.AddStep(() => { }, title, false, ExecutionOrder.TearDown, false, ""); return this; } + + public IFluentStepBuilder SetStepTitleFunction(Func customStepTitleCreatorFunction) + { + Configurator.Scanners.SetCustomStepTitleCreatorFunction(customStepTitleCreatorFunction); + return this; + } } -} \ No newline at end of file +} diff --git a/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/FluentScanner.cs b/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/FluentScanner.cs index 92e5f39..68cbc54 100644 --- a/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/FluentScanner.cs +++ b/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/FluentScanner.cs @@ -43,12 +43,31 @@ internal class FluentScanner : IFluentScanner private readonly TScenario _testObject; private readonly ITestContext _testContext; private readonly MethodInfo _fakeExecuteActionMethod; - + private Func _createTitle; internal FluentScanner(TScenario testObject) { - _testObject = testObject; + _testObject = testObject; _testContext = TestContext.GetContext(_testObject); _fakeExecuteActionMethod = typeof(FluentScanner).GetMethod("ExecuteAction", BindingFlags.Instance | BindingFlags.NonPublic); + + SetTitleFunction(); + } + + public void SetTitleFunction() + { + if (Configurator.Scanners.CustomStepTitleCreatorFunction != null) + { + _createTitle = Configurator.Scanners.CustomStepTitleCreatorFunction; + } + else + if (Configurator.Scanners.DefaultStepTitleCreatorFunction != null) + { + _createTitle = Configurator.Scanners.DefaultStepTitleCreatorFunction; + } + else + { + _createTitle = CreateTitle; + } } IScanner IFluentScanner.GetScanner(string scenarioTitle, Type explicitStoryType) @@ -89,13 +108,14 @@ public void AddStep(Expression> stepAction, bool reports, Ex AddStep(_ => compiledAction().Action(), expression, null, true, reports, executionOrder, asserts, stepPrefix); } + + [UsedImplicitly] [StepTitle("")] private void ExecuteAction(ExampleAction action) { - - } + } public void AddStep(Expression> stepAction, string stepTextTemplate, bool includeInputsInStepTitle, bool reports, ExecutionOrder executionOrder, bool asserts, string stepPrefix) { var action = stepAction.Compile(); @@ -105,9 +125,8 @@ public void AddStep(Expression> stepAction, string stepTex inputArguments = stepAction.ExtractArguments(_testObject).ToArray(); } - var title = CreateTitle(stepTextTemplate, includeInputsInStepTitle, GetMethodInfo(stepAction), inputArguments, stepPrefix); - var args = inputArguments.Where(s => !string.IsNullOrEmpty(s.Name)).ToList(); - _steps.Add(new Step(StepActionFactory.GetStepAction(action), title, FixAsserts(asserts, executionOrder), FixConsecutiveStep(executionOrder), reports, args)); + var args = inputArguments.Where(s => !string.IsNullOrEmpty(s.Name)).ToList(); + _steps.Add(new Step(stepAction, StepActionFactory.GetStepAction(action), _createTitle, stepTextTemplate,stepPrefix, includeInputsInStepTitle, GetMethodInfo, _testObject,null, FixAsserts(asserts, executionOrder), FixConsecutiveStep(executionOrder), reports, args)); } public void AddStep(Expression> stepAction, string stepTextTemplate, bool includeInputsInStepTitle, bool reports, ExecutionOrder executionOrder, bool asserts, string stepPrefix) @@ -126,10 +145,8 @@ private void AddStep(Action action, LambdaExpression stepAction, stri inputArguments = stepAction.ExtractArguments(_testObject).ToArray(); } - var title = CreateTitle(stepTextTemplate, includeInputsInStepTitle, GetMethodInfo(stepAction), inputArguments, - stepPrefix); - var args = inputArguments.Where(s => !string.IsNullOrEmpty(s.Name)).ToList(); - _steps.Add(new Step(StepActionFactory.GetStepAction(action), title, FixAsserts(asserts, executionOrder), + var args = inputArguments.Where(s => !string.IsNullOrEmpty(s.Name)).ToList(); + _steps.Add(new Step(stepAction, stepTextTemplate, includeInputsInStepTitle, GetMethodInfo, stepPrefix,_createTitle, StepActionFactory.GetStepAction(action), null, FixAsserts(asserts, executionOrder), FixConsecutiveStep(executionOrder), reports, args)); } @@ -177,46 +194,46 @@ private ExecutionOrder FixConsecutiveStep(ExecutionOrder executionOrder) private StepTitle CreateTitle(string stepTextTemplate, bool includeInputsInStepTitle, MethodInfo methodInfo, StepArgument[] inputArguments, string stepPrefix) { Func createTitle = () => - { + { - var flatInputArray = inputArguments.Select(o => o.Value).FlattenArrays(); - var name = methodInfo.Name; - var stepTitleAttribute = methodInfo.GetCustomAttributes(typeof(StepTitleAttribute), true).SingleOrDefault(); - if (stepTitleAttribute != null) - { - var titleAttribute = ((StepTitleAttribute)stepTitleAttribute); - name = string.Format(titleAttribute.StepTitle, flatInputArray); - if (titleAttribute.IncludeInputsInStepTitle != null) - includeInputsInStepTitle = titleAttribute.IncludeInputsInStepTitle.Value; - } + var flatInputArray = inputArguments.Select(o => o.Value).FlattenArrays(); + var name = methodInfo.Name; + var stepTitleAttribute = methodInfo.GetCustomAttributes(typeof(StepTitleAttribute), true).SingleOrDefault(); + if (stepTitleAttribute != null) + { + var titleAttribute = ((StepTitleAttribute)stepTitleAttribute); + name = string.Format(titleAttribute.StepTitle, flatInputArray); + if (titleAttribute.IncludeInputsInStepTitle != null) + includeInputsInStepTitle = titleAttribute.IncludeInputsInStepTitle.Value; + } - var stepTitle = AppendPrefix(Configurator.Scanners.Humanize(name), stepPrefix); + var stepTitle = AppendPrefix(Configurator.Scanners.Humanize(name), stepPrefix); - if (!string.IsNullOrEmpty(stepTextTemplate)) stepTitle = string.Format(stepTextTemplate, flatInputArray); - else if (includeInputsInStepTitle) - { - var parameters = methodInfo.GetParameters(); - var stringFlatInputs = - inputArguments - .Select((a, i) => new { ParameterName = parameters[i].Name, Value = a }) - .Select(i => + if (!string.IsNullOrEmpty(stepTextTemplate)) stepTitle = string.Format(stepTextTemplate, flatInputArray); + else if (includeInputsInStepTitle) + { + var parameters = methodInfo.GetParameters(); + var stringFlatInputs = + inputArguments + .Select((a, i) => new { ParameterName = parameters[i].Name, Value = a }) + .Select(i => + { + if (_testContext.Examples != null) { - if (_testContext.Examples != null) - { - var matchingHeader = _testContext.Examples.Headers - .SingleOrDefault(header => ExampleTable.HeaderMatches(header, i.ParameterName) || - ExampleTable.HeaderMatches(header, i.Value.Name)); - if (matchingHeader != null) - return string.Format("<{0}>", matchingHeader); - } - return i.Value.Value.FlattenArray(); - }) - .ToArray(); - stepTitle = stepTitle + " " + string.Join(", ", stringFlatInputs); - } + var matchingHeader = _testContext.Examples.Headers + .SingleOrDefault(header => ExampleTable.HeaderMatches(header, i.ParameterName) || + ExampleTable.HeaderMatches(header, i.Value.Name)); + if (matchingHeader != null) + return string.Format("<{0}>", matchingHeader); + } + return i.Value.Value.FlattenArray(); + }) + .ToArray(); + stepTitle = stepTitle + " " + string.Join(", ", stringFlatInputs); + } - return stepTitle.Trim(); - }; + return stepTitle.Trim(); + }; return new StepTitle(createTitle); } diff --git a/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/IFluentScanner.cs b/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/IFluentScanner.cs index 06c021e..81e2fa8 100644 --- a/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/IFluentScanner.cs +++ b/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/IFluentScanner.cs @@ -1,9 +1,11 @@ using System; +using System.Reflection; namespace TestStack.BDDfy { public interface IFluentScanner { IScanner GetScanner(string scenarioTitle, Type explicitStoryType); + void SetTitleFunction(); } } diff --git a/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/StepTitleExtension.cs b/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/StepTitleExtension.cs new file mode 100644 index 0000000..4cef951 --- /dev/null +++ b/src/TestStack.BDDfy/Scanners/StepScanners/Fluent/StepTitleExtension.cs @@ -0,0 +1,15 @@ +//using System; +//using System.Collections.Generic; +//using System.Reflection; +//using System.Text; + +//namespace TestStack.BDDfy.Scanners.StepScanners.Fluent +//{ +// public static class StepTitleExtension +// { +// public void void SetCreateTitle(this IFluentScanner fluentScanner,Func customCreateTitle); +// { +// fluentScanner.s +// } +// } +//} diff --git a/src/TestStack.BDDfy/Scanners/StepScanners/SetTitleExtensionMethod.cs b/src/TestStack.BDDfy/Scanners/StepScanners/SetTitleExtensionMethod.cs new file mode 100644 index 0000000..957c204 --- /dev/null +++ b/src/TestStack.BDDfy/Scanners/StepScanners/SetTitleExtensionMethod.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestStack.BDDfy.Scanners.StepScanners +{ + public static class SetTitleExtensionMethod + { + + } +} diff --git a/src/TestStack.BDDfy/Step.cs b/src/TestStack.BDDfy/Step.cs index ac331ed..5d91098 100644 --- a/src/TestStack.BDDfy/Step.cs +++ b/src/TestStack.BDDfy/Step.cs @@ -1,19 +1,31 @@ using System; using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; +using System.Threading.Tasks; using TestStack.BDDfy.Configuration; - +using System.Linq; namespace TestStack.BDDfy { public class Step { - private readonly StepTitle _title; + private StepTitle _title; + private LambdaExpression _stepAction; + private Func _createTitle; + private string _stepTextTemplate; + private string _stepPrefix; + private bool _includeInputsInStepTitle; + private Func _getMethodInfo; + private object _testObject; + private bool _reports; + public Step( Func action, StepTitle title, bool asserts, ExecutionOrder executionOrder, - bool shouldReport, + bool shouldReport, List arguments) { Id = Configurator.IdGenerator.GetStepId(); @@ -38,6 +50,54 @@ public Step(Step step) Arguments = step.Arguments; } + public Step(LambdaExpression stepAction, Func action, Func createTitle, string stepTextTemplate, string stepPrefix, bool includeInputsInStepTitle, Func getMethodInfo, object testObject, string title, bool assert, ExecutionOrder executionOrder, bool shouldReport, List args) + { + _stepAction = stepAction; + Action = action; + _createTitle = createTitle; + _stepTextTemplate = stepTextTemplate; + _includeInputsInStepTitle = includeInputsInStepTitle; + _getMethodInfo = getMethodInfo; + _testObject = testObject; + this.Asserts = assert; + ExecutionOrder = executionOrder; + ShouldReport = shouldReport; + Arguments = args; + _stepPrefix = stepPrefix; + } + + public Step(LambdaExpression stepAction, string stepTextTemplate, bool includeInputsInStepTitle, Func getMethodInfo, string stepPrefix, Func createTitle, Func action, StepTitle title, bool assert, ExecutionOrder executionOrder, bool shouldReport, List args) + { + _stepAction = stepAction; + _stepTextTemplate = stepTextTemplate; + _includeInputsInStepTitle = includeInputsInStepTitle; + _getMethodInfo = getMethodInfo; + _stepPrefix = stepPrefix; + Action = action; + _title = title; + Asserts = assert; + ExecutionOrder = executionOrder; + ShouldReport = shouldReport; + Arguments = args; + _createTitle = createTitle; + + } + + public void ResetTitle() + { + if (_stepAction != null) + { + var action = _stepAction.Compile(); + var inputArguments = new StepArgument[0]; + if (_includeInputsInStepTitle) + { + inputArguments = _stepAction.ExtractArguments(_testObject).ToArray(); + } + + _title = _createTitle(_stepTextTemplate, _includeInputsInStepTitle, _getMethodInfo(_stepAction), inputArguments, _stepPrefix); + } + } + public string Id { get; private set; } internal Func Action { get; set; } public bool Asserts { get; private set; } @@ -46,6 +106,14 @@ public string Title { get { + if (_title == null) + { + ResetTitle(); + } + if (_title == null) + { + return string.Empty; + } return _title.ToString(); } }