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

Cucumber Selenium中如何在不同Feature中复用相同步骤?

Cucumber Selenium中如何在不同Feature中复用相同步骤?

这个问题我之前也碰到过!核心问题就是公共步骤的Driver上下文没对应上——你把i am logged in放在A类里,跑B.feature的时候,B类的Driver还没初始化,而A类的@Before也不会因为执行B的场景而触发,导致步骤里的Driver实例未初始化报错。下面给你两个实用的解决方案:

方案一:用单例类统一管理Driver

把Driver的创建、销毁逻辑抽成一个全局管理类,所有步骤都通过这个类获取Driver,这样公共步骤就不用绑定到某个测试类了。

  1. 先创建Driver管理单例:
object DriverManager {
    lateinit var webDriver: WebDriver

    fun initDriver() {
        // 这里替换成你的Driver初始化逻辑,比如ChromeDriver
        webDriver = ChromeDriver()
    }

    fun quitDriver() {
        if (::webDriver.isInitialized) {
            webDriver.quit()
        }
    }
}
  1. 单独写公共步骤类,存放所有复用的步骤:
class CommonSteps {
    @Given("i am logged in")
    fun logInChecking() {
        DriverManager.webDriver.get("你的登录页面URL")
        // 这里补充登录的具体逻辑,比如输入账号密码、点击登录按钮等
    }
}
  1. 修改你的测试类,让它们通过DriverManager初始化/销毁Driver:
    A.kt:
class A {
    @Before
    fun setUp() {
        DriverManager.initDriver()
    }

    @After
    fun tearDown() {
        DriverManager.quitDriver()
    }

    @When("Step A")
    fun stepA() {
        // 用DriverManager.webDriver访问浏览器,执行Step A的逻辑
    }

    @Then("Result A")
    fun resultA() {
        // 结果断言逻辑
    }
}

B.kt(和A类结构一致):

class B {
    @Before
    fun setUp() {
        DriverManager.initDriver()
    }

    @After
    fun tearDown() {
        DriverManager.quitDriver()
    }

    @When("Step B")
    fun stepB() {
        // Step B的逻辑
    }

    @Then("Result B")
    fun resultB() {
        // 结果断言逻辑
    }
}

这样每个场景执行前,都会通过测试类的@Before初始化Driver,公共步骤里直接用DriverManager的实例,就不会出现上下文不匹配的问题了。

方案二:用Cucumber依赖注入(PicoContainer)

如果你的项目比较复杂,推荐用依赖注入的方式,让Cucumber自动为每个场景维护一个上下文,所有步骤类共享这个上下文里的Driver。

  1. 先在build.gradle里添加PicoContainer依赖(版本要和你的Cucumber版本一致):
testImplementation 'io.cucumber:cucumber-picocontainer:7.14.0' // 替换成你的Cucumber版本
  1. 创建一个测试上下文类,用来存放Driver实例:
class TestContext {
    lateinit var webDriver: WebDriver
}
  1. 所有步骤类(包括公共步骤)都通过构造函数注入TestContext:
    公共步骤类CommonSteps.kt:
class CommonSteps(private val testContext: TestContext) {
    @Given("i am logged in")
    fun logInChecking() {
        testContext.webDriver.get("你的登录页面URL")
        // 登录逻辑
    }
}

A.kt:

class A(private val testContext: TestContext) {
    @Before
    fun setUp() {
        testContext.webDriver = ChromeDriver()
    }

    @After
    fun tearDown() {
        testContext.webDriver.quit()
    }

    @When("Step A")
    fun stepA() {
        // 使用testContext.webDriver执行逻辑
    }

    // ...其他步骤
}

B.kt同理,只需要替换Step B和Result B的逻辑即可。

Cucumber会自动为每个场景创建一个独立的TestContext实例,所有关联的步骤类都会拿到同一个实例,这样Driver就会和当前场景的上下文绑定,不会出现错位的问题。

为什么之前的方法不行?

你之前把公共步骤放在A类里,当执行B.feature时,Cucumber会根据步骤匹配到A类的logInChecking方法,但此时A类的@Before注解方法并不会执行(因为@Before是属于A类的,只有执行A.feature的场景时才会触发),所以A类里的webDriver还没初始化,自然就抛出未初始化的错误了。

备注:内容来源于stack exchange,提问作者Mark

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 09:39:35