如何管理需要反复重用的步骤定义代码
How to manage the step definition code that needs to be reused again & again
我的功能文件包含一个功能,每个步骤定义文件都需要一次又一次地重复使用该功能。如何管理代码
我的特点是:-
"User is on home Page".
以上功能/场景包含需要反复使用的代码。在我的代码库中,对于每个功能文件,我都编写了单独的步骤定义。
我的第一步定义文件:-
@Given ("^user is on HomePage$")
public void user_homePage()
{
configFileReader =new ConfigFileReader();
System.setProperty("webdriver.chrome.driver","D:\chromedriver.exe");
driver=new ChromeDriver();
driver.get("https://parabank.parasoft.com/parabank/index.htm");
driver.manage().window().maximize();
}
现在需要在另一个步骤定义文件中使用相同的功能。 IE
下面
在用户点击 'Register' link 之前,它应该验证用户在主页上。 'User is on home page' 的描述在第一步定义文件中定义。
现在如何管理这里的代码:-
下面是我的第二步定义文件:-
导入 StepFiles。ParaBank_TC_01_Step; [我什至导入了第一步定义文件,因此可以执行该功能 "User is on home page"。 ]
public class ParaBank_TC_02_Step {
public WebDriver driver;
ConfigFileReader configFileReader;
@When ("^user clicks on register link$")
public void click_register() throws InterruptedException
{
Thread.sleep(3000);
WebElement register_link= driver.findElement(By.xpath("//a[contains(text(),'Register')]"));
register_link.click();
}
实际结果:-
1. 当我在一个文件中编写 2 个特征文件的所有步骤定义时,它执行得非常好,因为特征 'User is on home page' 是在同一个文件中定义的。
- 因为我在另一个 java 文件中为功能 2 编写了单独的步骤定义。它向我显示 "Null pointer exception" 错误,因为功能 "User is on home page" > 驱动程序在 1 步 def 文件中初始化。它没有为第二步定义文件执行。
请帮助我了解此问题的根本原因并提供最佳解决方案。
为了在步骤之间共享状态,您可以使用依赖注入 (DI)。 Cucumber 支持多种 DI 框架。我们建议您使用您的应用程序已经使用的/您熟悉的(在我的例子中,即 Spring)。否则,我们推荐 PicoContainer 作为最轻量级的选项。
您可以在 Cucumber docs 和 GitHub 上找到有关使用 DI 的更多信息。
有关使用 PicoContainer 的更多信息,请参阅此 blogpost。
要使用Spring,请看我的blogpost.
要使用 Guice,请查看此 blogpost。
旁注:
Feature-coupled 步骤定义(在单独的文件中为每个功能定义步骤定义,以便它们不能跨功能重复使用)被视为 anti-pattern,因为 "This may lead to an explosion of step definitions, code duplication, and high maintenance costs."
(来自Cucumber docs)。
解决方案是解耦您的步骤定义:
“
* 按领域概念组织您的步骤。
- 为您的步骤和步骤定义文件使用 domain-related 名称(而不是功能名称或 scenario-related 名称)。”
(来自Cucumber docs)。
为此,您需要使用 DI。
如果您有兴趣实现 PicoContainer,请按照以下步骤更好地理解 :
第 1 步。OrderSelectionStepDef 和 OrderDetailsStepDef 如下所示(请根据您的实施更改名称)
/**
* Step Definition implementation class for Cucumber Steps defined in Feature file
*/
public class HomePageSteps extends BaseSteps {
TestContext testContext;
public HomePageSteps(TestContext context) {
testContext = context;
}
@When("^User is on Brand Home Page (.+)$")
public void user_is_on_Brand_Home_Page(String siteName) throws InterruptedException {
homePage = new HomePage().launchBrandSite(siteName);
testContext.scenarioContext.setContext(Context.HOMEPAGE, homePage);
}
@Then("^Clicking on Sign In link shall take user to Sign In Page$")
public void clicking_on_Sign_In_link_shall_take_user_to_Sign_In_Page() {
homePage = (HomePage) testContext.scenarioContext.getContext(Context.HOMEPAGE);
signInPage = homePage.ecommSignInPageNavigation();
testContext.scenarioContext.setContext(Context.SIGNINPAGE, signInPage);
}
供大家参考
public class BaseSteps {
protected HomePage homePage;
protected PLPPage plpPage;
protected PDPPage pdpPage;
protected ShoppingBagPage shoppingBagPage;
protected ShippingPage shippingPage;
More implementation goes here.....
}
步骤2.请在你的框架下添加下面2个类 -
首先,Java文件名-ScenarioContext.java
public class ScenarioContext {
private Map<String, Object> scenarioContext;
public ScenarioContext(){
scenarioContext = new HashMap<String, Object>();
}
public void setContext(Context key, Object value) {
scenarioContext.put(key.toString(), value);
}
public Object getContext(Context key){
return scenarioContext.get(key.toString());
}
public Boolean isContains(Context key){
return scenarioContext.containsKey(key.toString());
}
}
二、Java文件名-TestContext.java
public class TestContext {
public ScenarioContext scenarioContext;
public TestContext(){
scenarioContext = new ScenarioContext();
}
public ScenarioContext getScenarioContext() {
return scenarioContext;
}
}
步骤 3. POM 依赖性 - picocontainer 应根据您的黄瓜版本
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>${cucumber.version}</version>
</dependency>
我的功能文件包含一个功能,每个步骤定义文件都需要一次又一次地重复使用该功能。如何管理代码
我的特点是:- "User is on home Page".
以上功能/场景包含需要反复使用的代码。在我的代码库中,对于每个功能文件,我都编写了单独的步骤定义。
我的第一步定义文件:-
@Given ("^user is on HomePage$")
public void user_homePage()
{
configFileReader =new ConfigFileReader();
System.setProperty("webdriver.chrome.driver","D:\chromedriver.exe");
driver=new ChromeDriver();
driver.get("https://parabank.parasoft.com/parabank/index.htm");
driver.manage().window().maximize();
}
现在需要在另一个步骤定义文件中使用相同的功能。 IE 下面
在用户点击 'Register' link 之前,它应该验证用户在主页上。 'User is on home page' 的描述在第一步定义文件中定义。
现在如何管理这里的代码:-
下面是我的第二步定义文件:-
导入 StepFiles。ParaBank_TC_01_Step; [我什至导入了第一步定义文件,因此可以执行该功能 "User is on home page"。 ]
public class ParaBank_TC_02_Step {
public WebDriver driver;
ConfigFileReader configFileReader;
@When ("^user clicks on register link$")
public void click_register() throws InterruptedException
{
Thread.sleep(3000);
WebElement register_link= driver.findElement(By.xpath("//a[contains(text(),'Register')]"));
register_link.click();
}
实际结果:- 1. 当我在一个文件中编写 2 个特征文件的所有步骤定义时,它执行得非常好,因为特征 'User is on home page' 是在同一个文件中定义的。
- 因为我在另一个 java 文件中为功能 2 编写了单独的步骤定义。它向我显示 "Null pointer exception" 错误,因为功能 "User is on home page" > 驱动程序在 1 步 def 文件中初始化。它没有为第二步定义文件执行。
请帮助我了解此问题的根本原因并提供最佳解决方案。
为了在步骤之间共享状态,您可以使用依赖注入 (DI)。 Cucumber 支持多种 DI 框架。我们建议您使用您的应用程序已经使用的/您熟悉的(在我的例子中,即 Spring)。否则,我们推荐 PicoContainer 作为最轻量级的选项。
您可以在 Cucumber docs 和 GitHub 上找到有关使用 DI 的更多信息。
有关使用 PicoContainer 的更多信息,请参阅此 blogpost。
要使用Spring,请看我的blogpost.
要使用 Guice,请查看此 blogpost。
旁注: Feature-coupled 步骤定义(在单独的文件中为每个功能定义步骤定义,以便它们不能跨功能重复使用)被视为 anti-pattern,因为 "This may lead to an explosion of step definitions, code duplication, and high maintenance costs." (来自Cucumber docs)。
解决方案是解耦您的步骤定义: “ * 按领域概念组织您的步骤。
- 为您的步骤和步骤定义文件使用 domain-related 名称(而不是功能名称或 scenario-related 名称)。” (来自Cucumber docs)。
为此,您需要使用 DI。
如果您有兴趣实现 PicoContainer,请按照以下步骤更好地理解 :
第 1 步。OrderSelectionStepDef 和 OrderDetailsStepDef 如下所示(请根据您的实施更改名称)
/**
* Step Definition implementation class for Cucumber Steps defined in Feature file
*/
public class HomePageSteps extends BaseSteps {
TestContext testContext;
public HomePageSteps(TestContext context) {
testContext = context;
}
@When("^User is on Brand Home Page (.+)$")
public void user_is_on_Brand_Home_Page(String siteName) throws InterruptedException {
homePage = new HomePage().launchBrandSite(siteName);
testContext.scenarioContext.setContext(Context.HOMEPAGE, homePage);
}
@Then("^Clicking on Sign In link shall take user to Sign In Page$")
public void clicking_on_Sign_In_link_shall_take_user_to_Sign_In_Page() {
homePage = (HomePage) testContext.scenarioContext.getContext(Context.HOMEPAGE);
signInPage = homePage.ecommSignInPageNavigation();
testContext.scenarioContext.setContext(Context.SIGNINPAGE, signInPage);
}
供大家参考
public class BaseSteps {
protected HomePage homePage;
protected PLPPage plpPage;
protected PDPPage pdpPage;
protected ShoppingBagPage shoppingBagPage;
protected ShippingPage shippingPage;
More implementation goes here.....
}
步骤2.请在你的框架下添加下面2个类 -
首先,Java文件名-ScenarioContext.java
public class ScenarioContext {
private Map<String, Object> scenarioContext;
public ScenarioContext(){
scenarioContext = new HashMap<String, Object>();
}
public void setContext(Context key, Object value) {
scenarioContext.put(key.toString(), value);
}
public Object getContext(Context key){
return scenarioContext.get(key.toString());
}
public Boolean isContains(Context key){
return scenarioContext.containsKey(key.toString());
}
}
二、Java文件名-TestContext.java
public class TestContext {
public ScenarioContext scenarioContext;
public TestContext(){
scenarioContext = new ScenarioContext();
}
public ScenarioContext getScenarioContext() {
return scenarioContext;
}
}
步骤 3. POM 依赖性 - picocontainer 应根据您的黄瓜版本
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>${cucumber.version}</version>
</dependency>