Serenity BDD如何复用@Steps测试步骤?(类Cucumber方式)
看起来你在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

