Cucumber java + Webdriver (8) 使用命令行风格来编写测试场景(Scenario)

8 篇文章 2 订阅
8 篇文章 0 订阅

团队最近采用了一种与之前的PageFactory思路完全不一样的模式来完成我们的自动化测试编码

 

在编写step过程中,有很多非常通用的步骤定义,这些步骤定义可编写大量与之类似的场景,而无需创建太多的步骤定义。

即采用一种命令式风格来编写场景步骤,使用fill,press这样的词语,对于这样一种风格有很多争议,但是不管好坏,尝试下总归是有好处的。

 这种命令式的风格,是属于用户界面控件的直接操作,所以我们会编写很多通用的step,而使用者只需要传入控件元素属性和其他对于值即可。

如 I fill in "Input_name" with "test"

意思是:在输入框“Input_name”中输入“test”

其中Input_name是对应元素的别称,我们把所有页面的元素都统一组织在一个文件里面去

 

下面就开始搭建该框架,以登录csdn为例子

1、在intellij idea创建一个Maven项KeyWordTest,在pom.xml添加依赖(参考之前文档)

2、创建对象库

在项目根目录下创建一个目录dataEngine,在该目录下创建一个文件ObjectRepository.properties,该文件用于保存CSDN各个页面上的元素对象

#该文件用于保存元素对象,每个Key是对应元素别称,Value是元素查找方式和查找值拼接,中间用英文符号":"分隔
#需要注意每个元素使用查找方式的Id,Name,Class,Xpath,CssSelector,LinkText,PartialLinkText,Tag是固定的

# Home Page Objects
Userbar_logout=LinkText:登录
Tag_body=Tag:body

#Login Page Objects
Input_name=Id:username
Input_password=Id:password
Login_button=Class:logging

3、解析上述元素对象

在项目的test->java下,创建目录com,在目录com中创建目录util

在目录util下创建WebDriverUtil.java
上述对象哭文件中,我们目的是用户在编写测试场景时,输入Input_name,底层代码可以直接定位到元素,则对该文件进行解析

所以,首先操作对象库

/** 操作对象库,根据传进来的Key,来获取Value
 * @param a(对应feature中传进来的元素名称即对应的是属性文件中的Key值)
 * @return(返回对应的values)
 */
public static String  readValue(String a){
    Properties defaultProperties = new Properties();
    String popath = "dataEngine/ObjectRepository.properties";
    String value=null;
    try {
        defaultProperties.load(new FileReader(popath));
        value = defaultProperties.getProperty(a);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }catch (IOException e) {
        e.printStackTrace();
    }
    return value;
}

之后根据获取到的Value,来获取元素的By值

/**
 * 根据对象库中的Value来获取By的值
 * @param field(对应feature中传进来的元素名称)
 * @return
 */
public static By getObjectLocator(String field) {
    String locatorProperty = readValue(field);
    System.out.println("解析该元素" + locatorProperty.toString());
    String locatorType = locatorProperty.split(":")[0];
    String locatorValue = locatorProperty.split(":")[1];

    By locator = null;
    if (locatorType.contains("Id")){
        locator = By.id(locatorValue);
    }else if (locatorType.contains("Name")){
        locator = By.name(locatorValue);
    }else if (locatorType.contains("Class")){
        locator = By.className(locatorValue);
    }else if (locatorType.contains("Xpath")){
        locator = By.xpath(locatorValue);
    } else if (locatorType.contains("CssSelector")){
        locator = By.cssSelector(locatorValue);
    }else if (locatorType.contains("LinkText")){
        locator = By.linkText(locatorValue);
    }else if (locatorType.contains("PartialLinkText")){
        locator = By.partialLinkText(locatorValue);
    }else if (locatorType.contains("Tag")){
        locator = By.tagName(locatorValue);
    }
    return locator;
}

然后再根据上面获取到的By值来定位到可见元素

则WebDriverUtil.java文件的完整代码:

import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;

import java.io.*;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

public class WebDriverUtil {

    /**
     * 该方法用于查找可见的元素
     * @param webDriver
     * @param field(对应feature中传进来的元素名称)
     * @return
     */
    public static WebElement findFieldWithToBeVisibility(WebDriver webDriver, String field) {
        try {
            Wait<WebDriver> wait = new FluentWait<WebDriver>(webDriver)
                    .withTimeout(30 * 1000, TimeUnit.MILLISECONDS)
                    .pollingEvery(500, TimeUnit.MILLISECONDS)
                    .ignoring(NoSuchElementException.class);

            final By locate = getObjectLocator(field);

            wait.until(ExpectedConditions.presenceOfElementLocated(locate));
            wait.until(ExpectedConditions.visibilityOfElementLocated(locate));
            return webDriver.findElement(locate);
        } catch(NoSuchElementException exception) {
            throw exception;
        }
    }

    /**
     * 根据对象库中的Value来获取By的值
     * @param field(对应feature中传进来的元素名称)
     * @return
     */
    public static By getObjectLocator(String field) {
        String locatorProperty = readValue(field);
        System.out.println("解析元素 " + field + "=" + locatorProperty.toString());
        String locatorType = locatorProperty.split(":")[0];
        String locatorValue = locatorProperty.split(":")[1];

        By locator = null;
        if (locatorType.contains("Id")){
            locator = By.id(locatorValue);
        }else if (locatorType.contains("Name")){
            locator = By.name(locatorValue);
        }else if (locatorType.contains("Class")){
            locator = By.className(locatorValue);
        }else if (locatorType.contains("Xpath")){
            locator = By.xpath(locatorValue);
        } else if (locatorType.contains("CssSelector")){
            locator = By.cssSelector(locatorValue);
        }else if (locatorType.contains("LinkText")){
            locator = By.linkText(locatorValue);
        }else if (locatorType.contains("PartialLinkText")){
            locator = By.partialLinkText(locatorValue);
        }else if (locatorType.contains("Tag")){
            locator = By.tagName(locatorValue);
        }
        return locator;
    }

    /** 操作对象库,根据传进来的Key,来获取Value
     * @param a(对应feature中传进来的元素名称即对应的是属性文件中的Key值)
     * @return(返回对应的values)
     */
    public static String  readValue(String a){
        Properties defaultProperties = new Properties();
        String popath = "dataEngine/ObjectRepository.properties";
        String value=null;
        try {
            defaultProperties.load(new FileReader(popath));
            value = defaultProperties.getProperty(a);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return value;
    }
}

则通过该文件,我们就解析了对象库,并获取到对应的元素位置

4、在util中创建一个类来启动driver

其中包括sharedriver.java、ConfigManager.java、custom.properties等文件
具体参考之前的文档:http://blog.csdn.net/yan1234abcd/article/details/49301577
目录结构如下所示:

5、接下来我们开始编写对这些元素对象的操作feature

在test目录下创建resources目录,并在该目录下创建features目录,目录结构如下所示

然后在该目录下创建一个文件login.feature,像编写测试用例步骤一样编写我们预期的step:

Feature: Login

  @login
  Scenario Outline: login in csdn
    #打开csdn首页
    Given I am on csdn
    #单击登录按钮
    And   I press "Userbar_login"
    #输入用户名
    And   I fill in "Input_name" with "<username>"
    #输入密码
    And   I fill in "Input_password" with "<password>"
    And   I press "Login_button"
    #登录成功后,可查到到用户名"echo_茵子",可以修改成自己的CSDN用户名
    Then  should see text "echo_茵子" in "Tag_body"

    Examples:
      |username     |password        |
      #这里输入对应的用户名和密码
      |*****        |*****           |

6、然后开始编写feature文件中对应的step的实现

这里我们先实现Given I am on csdn
在test->java->com目录下,创建目录stepDefs,在该目录下创建一个文件IAmOnStepDefs.java
import com.config.ConfigManager;
import com.util.SharedDriver;
import cucumber.api.java.en.Given;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;

import java.util.concurrent.TimeUnit;

public class IAmOnStepDefs {

    private final WebDriver driver;
    private final ConfigManager config;
    private static Wait<WebDriver> wait ;
    private static String baseUrl;

    public IAmOnStepDefs(SharedDriver driver, ConfigManager config) {
        this.driver = driver;
        this.config = config;
        wait = new FluentWait<WebDriver>(driver)
                .withTimeout(30, TimeUnit.SECONDS)
                .pollingEvery(500, TimeUnit.MILLISECONDS)
                .ignoring(NoSuchElementException.class);
    }

    /**
     *该方法用于实现csdn页面的跳转
     */
    @Given("^I am on csdn$")
    public void i_am_on() throws Throwable {

        baseUrl = this.config.get("base_path");
        this.driver.navigate().to(baseUrl);

        wait.until((new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver driverObject) {
                System.out.println("*****loading page*****");
                return (Boolean) ((JavascriptExecutor) driverObject).executeScript("return document.readyState === 'complete'");
            }
        }));
    }
}

7、运行程序,看下日志

可看到第一个step已经可以正常运行了,后面五个步骤还没定义

8、依次定义其他的步骤

创建IPressStepDefs.java,内容如下所示

import com.util.SharedDriver;
import com.util.WebDriverUtil;
import cucumber.api.java.en.When;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;

public class IPressStepDefs {

    private final WebDriver driver;

    public IPressStepDefs(SharedDriver driver) {
        this.driver = driver;
    }

    /**
     * 通过 field 找到某个元素,并进行点击
     */
    @When("^I press \"([^\"]*)\"$")
    public void i_press(String field) throws Throwable {
        WebElement element = WebDriverUtil.findFieldWithToBeVisibility(this.driver,field);
        new Actions(driver).moveToElement(element).perform();
        element.click();
    }
}
创建IFillInWithStepDefs.java,内容如下所示
import com.util.SharedDriver;
import com.util.WebDriverUtil;
import cucumber.api.java.en.When;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

public class IFillInWithStepDefs {

    private final WebDriver driver;

    public IFillInWithStepDefs(SharedDriver driver) {
        this.driver = driver;
    }

    /**
     * 通过 field 找到某个元素,并向该元素输入文字
     */
    @When("^I fill in \"([^\"]*)\" with \"([^\"]*)\"$")
    public void i_fill_in_with(String field, String content) throws Throwable {
        WebElement element = WebDriverUtil.findFieldWithToBeVisibility(this.driver,field);
        if (null != element) {
            element.clear();
            element.sendKeys(content);
        }
    }
}
创建ShouldSeeTextForElement.java,内容如下所示

import com.util.SharedDriver;
import com.util.WebDriverUtil;
import cucumber.api.java.en.Then;
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;

import java.util.concurrent.TimeUnit;

public class ShouldSeeTextForElement {

    private final WebDriver driver;
    private final Wait<WebDriver> wait;

    public ShouldSeeTextForElement(SharedDriver driver) {
        this.driver = driver;
        wait = new FluentWait<WebDriver>(this.driver)
                .withTimeout(30, TimeUnit.SECONDS)
                .pollingEvery(500, TimeUnit.MILLISECONDS)
                .ignoring(NoSuchElementException.class);
    }

    /**
     * 找到某个元素,并验证该元素存在内容text
     */
    @Then("^should see text \"([^\"]*)\" in \"([^\"]*)\"$")
    public void should_see_text(String text,String field) throws Throwable {
        try{
            WebElement element =  WebDriverUtil.findFieldWithToBeVisibility(driver,field);
            ((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView();", element);
            wait.until(ExpectedConditions.textToBePresentInElement(element,text));
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

则目前整个项目的目录结构如下所示:

9、运行程序,发现程序出错—中文乱码

这里是因为我们在对象库中使用了中文,默认情况下中文会被读成乱码,所以我们需要设置改下之前读取配置文件的代码:

/** 操作对象库,根据传进来的Key,来获取Value
 * @param a(对应feature中传进来的元素名称即对应的是属性文件中的Key值)
 * @return(返回对应的values)
 */
public static String  readValue(String a){
    Properties defaultProperties = new Properties();
    String popath = "dataEngine/ObjectRepository.properties";
    String value=null;
    try {
        InputStream in=new FileInputStream(popath);
        InputStreamReader re=new InputStreamReader(in,"GB2312");
        BufferedReader  bf=new BufferedReader(re);
        defaultProperties.load(bf);
        value = defaultProperties.getProperty(a);
        System.out.println(value);
        in.close(); // 关闭流

    } catch (Exception e) {
        e.printStackTrace();
    }
    return value;
}
之后使用MAVEN中再次运行程序,查看日志


则上述我们就搭建了一个采用命令行风格来编写测试场景的小框架,欢迎大家批评指正~

源代码在该链接,可免费下载:http://download.csdn.net/detail/yan1234abcd/9630675


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值