Search code examples
c#testingbddspecflow

SpecFlow BeforeScenario runs for each Feature file


I've only started to work with specflow and i know it's bindings are global for the assembly. Anyways, i couldn't find the solution or workaround for my problem:

  1. I use abstract class for my UI tests, such as

    public abstract class UITestBase<T>
        where T : FeatureContext, new()
    {
        private static readonly object SyncObject = new object();
        private static AutoTestSettings settings;
    
        private IWebDriver webDriver;
        private IBrowserFactory browserFactory;
        private Container container;
    
        protected static T Context;
    
        [BeforeScenario]
        public virtual void BeforeScenario()
        {
            BuildConfiguration();
    
            var driverPool = container.GetInstance<IWebDriverPool>();
            webDriver = driverPool.GetDriver(settings.BrowserType);
            browserFactory = container.GetInstance<IBrowserFactory>();
    
            Context = new T
                          {
                              Browser = browserFactory.Create(webDriver, settings.WebsiteUrl, settings.BrowserType),
                              Container = container
                          };
        }
    
        [AfterScenario]
        public virtual void AfterScenario()
        {
            webDriver.Dispose();
        }
    }
    
  2. I have few FeatureSteps files, one for each page/feature. E.g LoginFeature and PurchaseFeature. Each FeatureSteps class extends UITestBase and has [Binding] attribute.

  3. Whenever I run scenario for LoginFeature it seems to hook on BeforeScenario for PurchaseFeatureSteps as well. At least thats what Debug.WriteLine(this.GetType().Name) says.

  4. It causes that each scenario opens as many browsers as there are inheritors of UITestBase. Although tests are running fine it looks sorta ugly and feels wrong.

  5. Did anyone face such problem? How do I fix it?


Solution

  • As you noted, bindings are global in specflow. Also as you have discovered bindings in a base class are run once for each inheritor of that class. Don't place bindings into base classes, instead place them in a separate class specifically for this purpose, then Specflow will find them and run them. If you need to initialise objects for your scenarios to use, then I find its better to pass those objects through specflow's prescribed ways of sharing data between bindings. I have outlined an approach in this answer. My preference is for using context injection.

    If you have some setup which is specific to particular features or scenarios, then the bindings can be scoped so that they only run for particular features or scenarions