From 2391181b1930fa0234a7308279cfe723c1dc35ea Mon Sep 17 00:00:00 2001 From: Xerxes Battiwalla Date: Thu, 27 May 2010 17:06:12 +1000 Subject: [PATCH] Issue 41: NullReferenceException when using BeforeTestRun Modified StepMethodBinding to create a culture for the feature if one doesn't exist --- Runtime/Bindings/StepMethodBinding.cs | 13 +- .../BeforeAfterHooks/BeforeAfterHooks.feature | 25 ++++ .../BeforeAfterHooks.feature.cs | 132 ++++++++++++++++++ .../BeforeAfterHooks/BeforeAfterHooksSteps.cs | 121 ++++++++++++++++ Tests/FeatureTests/FeatureTests.csproj | 43 ++++++ 5 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooks.feature create mode 100644 Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooks.feature.cs create mode 100644 Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooksSteps.cs diff --git a/Runtime/Bindings/StepMethodBinding.cs b/Runtime/Bindings/StepMethodBinding.cs index 7a6d3ce62..309ffa535 100644 --- a/Runtime/Bindings/StepMethodBinding.cs +++ b/Runtime/Bindings/StepMethodBinding.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -121,7 +122,7 @@ public object InvokeAction(object[] arguments, ITestTracer testTracer, out TimeS { object result; Stopwatch stopwatch = new Stopwatch(); - using (new CultureInfoScope(FeatureContext.Current.FeatureInfo.Language)) + using (CreateCultureInfoScope()) { stopwatch.Start(); result = BindingAction.DynamicInvoke(arguments); @@ -148,6 +149,16 @@ public object InvokeAction(object[] arguments, ITestTracer testTracer, out TimeS } } + private CultureInfoScope CreateCultureInfoScope() + { + var cultureInfo = CultureInfo.CurrentCulture; + if (FeatureContext.Current != null) + { + cultureInfo = FeatureContext.Current.FeatureInfo.Language; + } + return new CultureInfoScope(cultureInfo); + } + internal void PreserveStackTrace(Exception ex) { typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(ex, new object[0]); diff --git a/Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooks.feature b/Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooks.feature new file mode 100644 index 000000000..04b5af801 --- /dev/null +++ b/Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooks.feature @@ -0,0 +1,25 @@ +Feature: Addition + As a developer + I would like to be able to hook into pre and post conditions in SpecFlow + So that I can set up and teardown my scenario accordingly + +Scenario: Hooking into pre conditions for Test Runs in SpecFlow + Given the scenario is running + Then the BeforeTestRun hook should have been executed + +Scenario: Hooking into pre conditions for Features in SpecFlow + Given the scenario is running + Then the BeforeFeature hook should have been executed + +Scenario: Hooking into pre conditions for Scenarios in SpecFlow + Given the scenario is running + Then the BeforeScenario hook should have been executed + +Scenario: Hooking into pre conditions for ScenarioBlocks in SpecFlow + Given the scenario is running + Then the BeforeScenarioBlock hook should have been executed + +Scenario: Hooking into pre conditions for Steps in SpecFlow + Given the scenario is running + Then the BeforeStep hook should have been executed + diff --git a/Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooks.feature.cs b/Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooks.feature.cs new file mode 100644 index 000000000..a24769f20 --- /dev/null +++ b/Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooks.feature.cs @@ -0,0 +1,132 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by SpecFlow (http://www.specflow.org/). +// SpecFlow Version:1.3.0.0 +// Runtime Version:4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +#region Designer generated code +namespace TechTalk.SpecFlow.FeatureTests.BeforeAfterHooks +{ + using TechTalk.SpecFlow; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.3.0.0")] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [NUnit.Framework.TestFixtureAttribute()] + [NUnit.Framework.DescriptionAttribute("Addition")] + public partial class AdditionFeature + { + + private static TechTalk.SpecFlow.ITestRunner testRunner; + +#line 1 "BeforeAfterHooks.feature" +#line hidden + + [NUnit.Framework.TestFixtureSetUpAttribute()] + public virtual void FeatureSetup() + { + testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); + TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Addition", "As a developer\r\nI would like to be able to hook into pre and post conditions in S" + + "pecFlow\r\nSo that I can set up and teardown my scenario accordingly", ((string[])(null))); + testRunner.OnFeatureStart(featureInfo); + } + + [NUnit.Framework.TestFixtureTearDownAttribute()] + public virtual void FeatureTearDown() + { + testRunner.OnFeatureEnd(); + testRunner = null; + } + + public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo) + { + testRunner.OnScenarioStart(scenarioInfo); + } + + [NUnit.Framework.TearDownAttribute()] + public virtual void ScenarioTearDown() + { + testRunner.OnScenarioEnd(); + } + + [NUnit.Framework.TestAttribute()] + [NUnit.Framework.DescriptionAttribute("Hooking into pre conditions for Test Runs in SpecFlow")] + public virtual void HookingIntoPreConditionsForTestRunsInSpecFlow() + { + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Hooking into pre conditions for Test Runs in SpecFlow", ((string[])(null))); +#line 6 +this.ScenarioSetup(scenarioInfo); +#line 7 +testRunner.Given("the scenario is running"); +#line 8 +testRunner.Then("the BeforeTestRun hook should have been executed"); +#line hidden + testRunner.CollectScenarioErrors(); + } + + [NUnit.Framework.TestAttribute()] + [NUnit.Framework.DescriptionAttribute("Hooking into pre conditions for Features in SpecFlow")] + public virtual void HookingIntoPreConditionsForFeaturesInSpecFlow() + { + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Hooking into pre conditions for Features in SpecFlow", ((string[])(null))); +#line 10 +this.ScenarioSetup(scenarioInfo); +#line 11 +testRunner.Given("the scenario is running"); +#line 12 +testRunner.Then("the BeforeFeature hook should have been executed"); +#line hidden + testRunner.CollectScenarioErrors(); + } + + [NUnit.Framework.TestAttribute()] + [NUnit.Framework.DescriptionAttribute("Hooking into pre conditions for Scenarios in SpecFlow")] + public virtual void HookingIntoPreConditionsForScenariosInSpecFlow() + { + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Hooking into pre conditions for Scenarios in SpecFlow", ((string[])(null))); +#line 14 +this.ScenarioSetup(scenarioInfo); +#line 15 +testRunner.Given("the scenario is running"); +#line 16 +testRunner.Then("the BeforeScenario hook should have been executed"); +#line hidden + testRunner.CollectScenarioErrors(); + } + + [NUnit.Framework.TestAttribute()] + [NUnit.Framework.DescriptionAttribute("Hooking into pre conditions for ScenarioBlocks in SpecFlow")] + public virtual void HookingIntoPreConditionsForScenarioBlocksInSpecFlow() + { + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Hooking into pre conditions for ScenarioBlocks in SpecFlow", ((string[])(null))); +#line 18 +this.ScenarioSetup(scenarioInfo); +#line 19 +testRunner.Given("the scenario is running"); +#line 20 +testRunner.Then("the BeforeScenarioBlock hook should have been executed"); +#line hidden + testRunner.CollectScenarioErrors(); + } + + [NUnit.Framework.TestAttribute()] + [NUnit.Framework.DescriptionAttribute("Hooking into pre conditions for Steps in SpecFlow")] + public virtual void HookingIntoPreConditionsForStepsInSpecFlow() + { + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Hooking into pre conditions for Steps in SpecFlow", ((string[])(null))); +#line 22 +this.ScenarioSetup(scenarioInfo); +#line 23 +testRunner.Given("the scenario is running"); +#line 24 +testRunner.Then("the BeforeStep hook should have been executed"); +#line hidden + testRunner.CollectScenarioErrors(); + } + } +} +#endregion diff --git a/Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooksSteps.cs b/Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooksSteps.cs new file mode 100644 index 000000000..67185f5e4 --- /dev/null +++ b/Tests/FeatureTests/BeforeAfterHooks/BeforeAfterHooksSteps.cs @@ -0,0 +1,121 @@ +using System; +using NUnit.Framework; + +namespace TechTalk.SpecFlow.FeatureTests.BeforeAfterHooks +{ + [Binding] + public class BeforeAfterHooksSteps + { + private static bool _beforeTestRunHookExecuted; + private static bool _beforeFeatureHookExecuted; + private bool _beforeScenarioHookExecuted; + private bool _beforeScenarioBlockHookExecuted; + private bool _beforeStepHookExecuted; + private static bool _afterFeatureHookExecuted; + private static bool _afterScenarioHookExecuted; + private static bool _afterScenarioBlockHookExecuted; + private static bool _afterStepHookExecuted; + + [BeforeTestRun] + public static void BeforeTestRun() + { + _beforeTestRunHookExecuted = true; + } + + [BeforeFeature] + public static void BeforeFeature() + { + _beforeFeatureHookExecuted = true; + } + + [BeforeScenario] + public void BeforeScenario() + { + _beforeScenarioHookExecuted = true; + } + + [BeforeScenarioBlock] + public void BeforeScenarioBlock() + { + _beforeScenarioBlockHookExecuted = true; + } + + [BeforeStep] + public void BeforeStep() + { + _beforeStepHookExecuted = true; + } + + [AfterTestRun] + public static void AfterTestRun() + { + // Testing AfterTestRun is tricky as it would probably involve manipulating the AppDomain + // Its been manually tested and verified that this code block is hit, but if something changes + // which stops it from being called, we'll never know... + + Assert.That(_afterFeatureHookExecuted, Is.True); + Assert.That(_afterScenarioHookExecuted, Is.True); + Assert.That(_afterScenarioBlockHookExecuted, Is.True); + Assert.That(_afterStepHookExecuted, Is.True); + } + + [AfterFeature] + public static void AfterFeature() + { + _afterFeatureHookExecuted = true; + } + + [AfterScenario] + public void AfterScenario() + { + _afterScenarioHookExecuted = true; + } + + [AfterScenarioBlock] + public void AfterScenarioBlock() + { + _afterScenarioBlockHookExecuted = true; + } + + [AfterStep] + public void AfterStep() + { + _afterStepHookExecuted = true; + } + + [Given(@"the scenario is running")] + public void GivenTheScenarioIsRunning() + { + } + + [Then(@"the BeforeTestRun hook should have been executed")] + public void ThenTheBeforeTestRunHookShouldHaveBeenExecuted() + { + Assert.That(_beforeTestRunHookExecuted, Is.True); + } + + [Then(@"the BeforeFeature hook should have been executed")] + public void ThenTheBeforeFeatureHookShouldHaveBeenExecuted() + { + Assert.That(_beforeFeatureHookExecuted, Is.True); + } + + [Then(@"the BeforeScenario hook should have been executed")] + public void ThenTheBeforeScenarioHookShouldHaveBeenExecuted() + { + Assert.That(_beforeScenarioHookExecuted, Is.True); + } + + [Then(@"the BeforeScenarioBlock hook should have been executed")] + public void ThenTheBeforeScenarioBlockHookShouldHaveBeenExecuted() + { + Assert.That(_beforeScenarioBlockHookExecuted, Is.True); + } + + [Then(@"the BeforeStep hook should have been executed")] + public void ThenTheBeforeStepHookShouldHaveBeenExecuted() + { + Assert.That(_beforeStepHookExecuted, Is.True); + } + } +} \ No newline at end of file diff --git a/Tests/FeatureTests/FeatureTests.csproj b/Tests/FeatureTests/FeatureTests.csproj index f61a0fda2..170388ebe 100644 --- a/Tests/FeatureTests/FeatureTests.csproj +++ b/Tests/FeatureTests/FeatureTests.csproj @@ -15,6 +15,21 @@ true + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true true @@ -51,6 +66,12 @@ + + True + True + BeforeAfterHooks.feature + + True True @@ -103,6 +124,10 @@ + + SpecFlowSingleFileGenerator + BeforeAfterHooks.feature.cs + SpecFlowSingleFileGenerator CallingStepsFromStepDefinition.feature.cs @@ -120,6 +145,24 @@ StepArgumentTransformation.feature.cs + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + +