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

Serenity BDD如何复用@Steps测试步骤?(类Cucumber方式)

解决Serenity BDD中跨步骤类复用步骤的问题

看起来你在Serenity里尝试复用不同页面的步骤时遇到了两个典型问题:要么浏览器提前关闭导致后续步骤失败,要么步骤不在报告中显示。下面给你几个可行的解决方案,帮你实现像Cucumber那样的步骤复用:

方案1:修复浏览器提前关闭问题(确保步骤类共享WebDriver实例)

你第一个方案的核心问题是步骤类没有正确复用同一个WebDriver会话,或者重复的页面初始化逻辑导致Serenity误判场景结束。按照以下方式调整:

1. 清理步骤类中的重复初始化逻辑

看你的StepsLoginPage代码,Launch()和Login_ValidCredential()都调用了login.Launch(),这会导致重复加载登录页面,甚至重置会话。修改Login_ValidCredential(),移除重复的页面启动调用:

public class StepsLoginPage extends ScenarioSteps {
    private static final long serialVersionUID = 1L;
    LoginPage login;

    @Step
    public void Launch() {
        login.Launch(); // 仅负责打开登录页面URL
    }

    @Step
    public void Login_ValidCredential() {
        // 移除重复的login.Launch(),测试类中已单独调用stepL.Launch()
        login.Enter_Username();
        login.Enter_Password();
        login.Click_LoginBtn();
    }
}

2. 确认测试类的WebDriver配置正确

你的测试类@Managed配置没问题,但要确保所有步骤类都继承自ScenarioSteps——Serenity会自动为ScenarioSteps子类注入@Managed的WebDriver实例,确保它们共用同一个浏览器会话:

public class AA_NameCheck{
    @Managed(driver="edge", clearCookies=ClearCookiesPolicy.BeforeEachTest)
    WebDriver driver;

    @Steps
    StepsLoginPage stepL;
    StepsNameCheckPage stepN;

    @Test
    public void NameCheck_ValidUser() throws InterruptedException{
        stepL.Launch();
        stepL.Login_ValidCredential();
        // 现在浏览器会保持打开,执行后续步骤
        stepN.Enter_NameDetails();
    }
}

方案2:在步骤类中注入其他步骤类(更优雅的复用方式)

如果你想更贴近Cucumber的步骤复用体验,可以在一个步骤类中直接注入另一个步骤类,这样测试类只需要依赖一个主步骤类,代码更简洁:

1. 修改StepsNameCheckPage,注入登录步骤类

public class StepsNameCheckPage extends ScenarioSteps{
    private static final long serialVersionUID = 1L;
    NameCheckPage namechk;

    // 直接注入Login步骤类
    @Steps
    StepsLoginPage stepL;

    @Step
    public void CompleteLoginAndNameCheck() throws InterruptedException {
        // 复用Login的步骤
        stepL.Launch();
        stepL.Login_ValidCredential();
        // 执行当前页面的操作
        namechk.Enter_FirstEngName();
        namechk.AddCompany();
        namechk.Enter_SecEngName();
        namechk.AddCompany();
        namechk.Enter_ThirdEngName();
        namechk.PrelimCheck();
    }
}

2. 测试类简化为只依赖一个步骤类

public class AA_NameCheck{
    @Managed(driver="edge", clearCookies=ClearCookiesPolicy.BeforeEachTest)
    WebDriver driver;

    @Steps
    StepsNameCheckPage stepN;

    @Test
    public void NameCheck_ValidUser() throws InterruptedException{
        stepN.CompleteLoginAndNameCheck();
    }
}

这种方式不仅实现了步骤复用,Serenity报告会完整记录所有带@Step注解的方法,包括登录环节的步骤。

方案3:使用Serenity Tasks模式(进阶复用方案)

如果你的业务步骤更复杂,推荐使用Serenity的Tasks模式,把重复流程封装成可复用的任务,比如创建一个LoginWithValidCredentials任务:

public class LoginWithValidCredentials implements Task {
    public static LoginWithValidCredentials perform() {
        return Tasks.instrumented(LoginWithValidCredentials.class);
    }

    @Override
    public <T extends Actor> void performAs(T actor) {
        actor.attemptsTo(
            Open.browserOn().the(LoginPage.class),
            Enter.theValue("valid-username").into(LoginPage.USERNAME),
            Enter.theValue("valid-password").into(LoginPage.PASSWORD),
            Click.on(LoginPage.LOGIN_BUTTON)
        );
    }
}

然后在步骤类或测试类中调用:

actor.attemptsTo(LoginWithValidCredentials.perform());

这种方式更符合Serenity的分层设计理念,步骤复用性更强,测试报告也会清晰展示任务中的每个操作细节。

为什么第二种方案(@Steps放在POM中)不可行?

Serenity的测试报告只会追踪ScenarioSteps子类中的@Step注解方法,页面对象(POM)的核心职责是封装页面元素和底层操作,把@Steps放在POM里不符合Serenity的分层结构,因此这些步骤不会被记录到报告中,不推荐这种做法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:01:47