You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpecFlow多场景运行重复打开浏览器问题求助

解决SpecFlow多场景运行时重复打开浏览器的问题

问题描述

我创建了包含2个场景的Feature文件,并编写了对应的Step Definitions,但运行时会打开多个浏览器,希望全程仅使用一个浏览器实例完成所有测试。

Feature代码

Feature: Login

Background: 
Given user navigated to SauceLap website

@Login
Scenario: user login with locked user
    When user enter the locked userName "locked_out_user"
    And  user enter the password "secret_sauce"
    And click on login button
    Then An error message must be appears
@Login
Scenario: user login with valid credentials
    When user enter a valid userName "standard_user"
    And  user enter a valid password "secret_sauce"
    And user click on login button
    Then automatically navigated to homePage

Step Definitions代码

namespace SpecFlowProject2.StepDefinitions
{
    [Binding]
    public sealed class Login
    {
        private IWebDriver driver;
        public Login(IWebDriver driver)
        {
            this.driver = driver;
        }

        [Given(@"user navigated to SauceLap website")]
        public void GivenUserNavigatedToSauceLapWebsite()
        {
           
            driver.Url = "https://www.saucedemo.com/v1/";
        }

        [When(@"user enter the locked userName ""([^""]*)""")]
        public void WhenUserEnterTheLockedUserName(string userName)
        {
            driver.FindElement(By.XPath("//input[@id='user-name']")).SendKeys(userName);
        }

        [When(@"user enter the password ""([^""]*)""")]
        public void WhenUserEnterThePassword(string Password)
        {
           driver.FindElement(By.Id("password")).SendKeys(Password);
        }

        [When(@"click on login button")]
        public void WhenClickOnLoginButton()
        {
           driver.FindElement(By.Id("login-button")).Click();
        }

        [Then(@"An error message must be appears")]
        public void ThenAnErrorMessageMustBeAppears()
        {
            Thread.Sleep(3000);
        }

        [When(@"user enter a valid userName ""([^""]*)""")]
        public void WhenUserEnterAValidUserName(string userName)
        {
            driver.FindElement(By.XPath("//input[@id='user-name']")).SendKeys(userName);
        }

        [When(@"user enter a valid password ""([^""]*)""")]
        public void WhenUserEnterAValidPassword(string Password)
        {
            driver.FindElement(By.Id("password")).SendKeys(Password);
        }

        [When(@"user click on login button")]
        public void WhenUserClickOnLoginButton()
        {
            driver.FindElement(By.Id("login-button")).Click();
        }

        [Then(@"automatically navigated to homePage")]
        public void ThenAutomaticallyNavigatedToHomePage()
        {
            Thread.Sleep(3000);
        }
    }
}

原Hooks代码

namespace SpecFlowProject2.Hook
{
    [Binding]
    public sealed class Hooks1
    {
        private readonly IObjectContainer _container;

        public Hooks1(IObjectContainer container)
        {
            _container = container; 
        }

        [BeforeScenario("@tag1")]
        public void BeforeScenarioWithTag()
        {
            // Example of filtering hooks using tags. (in this case, this 'before scenario' hook will execute if the feature/scenario contains the tag '@tag1')
            // See https://docs.specflow.org/projects/specflow/en/latest/Bindings/Hooks.html?highlight=hooks#tag-scoping

            //TODO: implement logic that has to run before executing each scenario
        }

        [BeforeFeature(Order = 1)]
        public  void FirstBeforeScenario()
        {
            IWebDriver driver=new ChromeDriver();
            driver.Manage().Window.Maximize();
            _container.RegisterInstanceAs<IWebDriver>(driver);
        }

        [AfterScenario]
        public void AfterScenario()
        {
            //TODO: implement logic that has to run after executing each scenario
        }
    }
}

问题原因

原代码使用[BeforeFeature]钩子初始化浏览器,但该钩子作用域为单个Feature,且依赖注入容器的实例注册逻辑无法保证多个场景间复用同一个WebDriver实例,导致每个场景运行时都会重新创建浏览器实例。

解决方案

修改Hooks代码,通过全局测试周期钩子控制WebDriver生命周期,确保全程复用一个浏览器实例,并在场景间重置状态避免污染:

修改后的Hooks代码

namespace SpecFlowProject2.Hook
{
    [Binding]
    public sealed class Hooks1
    {
        private static IWebDriver _driver;
        private readonly IObjectContainer _container;

        public Hooks1(IObjectContainer container)
        {
            _container = container; 
        }

        [BeforeTestRun]
        public static void BeforeTestRun()
        {
            // 所有测试开始前仅初始化一次浏览器
            _driver = new ChromeDriver();
            _driver.Manage().Window.Maximize();
        }

        [BeforeScenario]
        public void BeforeScenario()
        {
            // 将单例浏览器实例注册到容器,供当前场景的Step Definitions使用
            _container.RegisterInstanceAs<IWebDriver>(_driver);
        }

        [AfterScenario]
        public void AfterScenario()
        {
            // 场景执行后重置浏览器状态,避免场景间数据残留
            _driver.Navigate().GoToUrl("https://www.saucedemo.com/v1/");
            _driver.FindElement(By.Id("user-name")).Clear();
            _driver.FindElement(By.Id("password")).Clear();
        }

        [AfterTestRun]
        public static void AfterTestRun()
        {
            // 所有测试完成后关闭浏览器,释放资源
            _driver?.Quit();
            _driver?.Dispose();
        }
    }
}

关键修改说明

  1. [BeforeTestRun]钩子:在整个测试套件启动时仅执行一次,初始化全局单例WebDriver实例,保证全程复用同一个浏览器。
  2. [BeforeScenario]钩子:每个场景开始前将全局单例driver注册到容器,确保当前场景的所有Step Definitions都获取同一个实例。
  3. [AfterScenario]钩子:场景结束后重置浏览器到初始状态(回到登录页、清除输入框),避免前一个场景的操作影响后续场景。
  4. [AfterTestRun]钩子:所有测试执行完毕后关闭浏览器,释放系统资源,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Mohamed hakim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 10:27:03