Selenium selenium 入门学习 (三)

顺流而下 · 2017年07月27日 · 最后由 顺流而下 回复于 2017年08月18日 · 4084 次阅读

前文链接

学习三 -- 对参数变量进行优化

使用 @DataProvider 注解对参数优化

通过注解把业务参数从代码中分离出来,这样做有以下优点:

  • 使得代码可以重复使用;
  • 每一个测试 TEST 代码可以变成对一个测试点的描述,对业务的描述;
  • 每一组测试数据可以针对同一个测试点进行不同场景测试;

    public class SeleniumTest1 {
    WebDriver webDriver;
    
    @BeforeMethod
    public void beforMethod() throws IOException {
        // 业务无关,启动配置相关代码
        String driverPath = new File("./").getCanonicalPath() + "/src/main/resources/driver/chromedriver.exe";
        System.setProperty("webdriver.chrome.driver", driverPath);
        webDriver = new ChromeDriver();
        webDriver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
    }
    
        // 使用注解,参数化用例
    @DataProvider(name = "selenium_data1")
    public Iterator<Object[]> dataProvider() {
        Set<Object[]> set = new HashSet<Object[]>();
        // 通过添加不同数据可以对一个测试点进行一组测试用例的测试
        set.add(new String[] { "zhangsan", "password", "true" });
        set.add(new String[] { "lisi", "password", "false" });
    
        return set.iterator();
    }
    
    @Test(dataProvider = "selenium_data1") //指定使用的数据驱动是selenium_data1;
    public void test(String username, String password, String expected)  // 参数是对应的set中每个单元的值
       {
        webDriver.get("https://www.baidu.com/");
        webDriver.manage().window().maximize();
        webDriver.findElement(By.xpath("//*[@id='u1']/a[7]")).click();
        webDriver.findElement(By.id("TANGRAM__PSP_10__userName")).sendKeys(username);
        webDriver.findElement(By.id("TANGRAM__PSP_10__password")).sendKeys(password);
        webDriver.findElement(By.id("TANGRAM__PSP_10__verifyCode")).sendKeys("验证码");
        webDriver.findElement(By.id("TANGRAM__PSP_10__submit")).click();
        boolean result = webDriver.findElement(By.id("user-name")).getText().contains(username);
        if (expected.equals("true")) {
            assert result;
        } else {
            assert !result;
        }
    }
    @AfterMethod
    public void afterMethod() {
        // 业务无关代码
        webDriver.quit();
    }
    }
    

    封装业务变量

    抽出 Elements 定位使用的变量:
    单独的类存放定位参数:

    public class HomePage {
    public static final String byXpathButtonLogin = "//*[@id='u1']/a[7]";
    public static final String byIdInputName = "TANGRAM__PSP_10__userName";
    public static final String byIdInputPassword = "TANGRAM__PSP_10__password";
    public static final String byIdInputVerifyCode = "TANGRAM__PSP_10__verifyCode";
    public static final String byIdButtonSubmit = "TANGRAM__PSP_10__submit";
    public static final String byIdTextName = "user-name";
    }
    
    public class SeleniumTest1 {
    WebDriver webDriver;
    
    @BeforeMethod
    public void beforMethod() throws IOException {
        // 业务无关,启动配置相关代码
        String driverPath = new File("./").getCanonicalPath() + "/src/main/resources/driver/chromedriver.exe";
        System.setProperty("webdriver.chrome.driver", driverPath);
        webDriver = new ChromeDriver();
        webDriver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
    }
    
    @Test(dataProvider = "selenium_data1")
    public void test(String username, String password, String expected) {
    
        webDriver.get("https://www.baidu.com/");
        webDriver.manage().window().maximize();
        webDriver.findElement(By.xpath(HomePage.byXpathButtonLogin)).click();
        webDriver.findElement(By.id(HomePage.byIdInputName)).sendKeys(username);
        webDriver.findElement(By.id(HomePage.byIdInputPassword)).sendKeys(password);
        webDriver.findElement(By.id(HomePage.byIdInputVerifyCode)).sendKeys("验证码");
        webDriver.findElement(By.id(HomePage.byIdButtonSubmit)).click();
        boolean result = webDriver.findElement(By.id(HomePage.byIdTextName)).getText().contains(username);
        if (expected.equals("true")) {
            assert result;
        } else {
            assert !result;
        }
    }
    
    // set的每一个数据迭代就相当于一个用例
    @DataProvider(name = "selenium_data1")
    public Iterator<Object[]> dataProvider() {
        Set<Object[]> set = new HashSet<Object[]>();
        // 通过添加不同数据可以对一个测试点进行一组测试用例的测试
        set.add(new String[] { "zhangsan", "password", "true" });
        set.add(new String[] { "lisi", "password", "false" });
    
        return set.iterator();
    }
    @AfterMethod
    public void afterMethod() {
        // 业务无关代码
        webDriver.quit();
    }
    }
    

这样一个大致的 UI 自动化算是完成了,还存在一些问题

  • 测试报告怎么体现出来
  • 驱动数据存放在代码中不易维护
  • 页面元素定位维护和定位代码遇到修改比较麻烦
  • 怎么去执行,手动执行用例显然不合适
共收到 7 条回复 时间 点赞

坐等更新~~~~

在吴晓华的 selenium webdriver 一书 11 章有说到

初痕 回复

说的啥内容啊

白纸 回复

尽力哈

顺流而下 selenium 入门学习 (四) 中提及了此贴 08月07日 16:06

关于:页面元素定位维护和定位代码遇到修改比较麻烦
1.可以把 By.id/name/className 等等这些定位方式,封装成一个方法 By by(String by,String local):参数为定位方式和元素位置

public By by (String by,String local){

        if(by.equals("id")){
            return By.id(local);
        }else if(by.equals("name")){
            return By.name(local);
        }else if(by.equals("className")){
            return By.className(local);
        }else{
            return By.xpath(local);
        }
    }
  1. findElement(By.id(“....”)),其实也可以封装
public WebElement element(By by) {
        WebElement ele = driver.findElement(by);
        return ele;
    }

那么上边的 webDriver.findElement(By.xpath(HomePage.byXpathButtonLogin)) 元素定位的代码可以更新为:

//定义变量:登录按钮的定位方式为xpath;定位值为:byXpathButtonLogin ( "//*[@id='u1']/a[7]")
String loginBy = ''xpath";
Sting LoginButtonElement = "//*[@id='u1']/a[7]";

WebElement loginButton = this.element(this.by(loginBy ,LoginButtonElement ))
//其他元素类似
//。。。。。。

以上代码,还可以进一步使用读取配置文件来封装以简化代码
具体思路就是:

将定位方式 By(String by,String local) 简化为 By(String valueElement),而具体的定位方式和定位值用配置文件来读取

public By by(String valueElement) throws Exception {

        // 读取配置文件内容
        ProUtil properties = new ProUtil("element.properties");
        String locator = properties.getPro(valueElement);
        // 定位第一个值
        String locatorType = locator.split(">")[0];
        // 定位第二个值
        String locatorValue = locator.split(">")[1];

        if (locatorType.equals("id")) {
            return By.id(locatorValue);
        } else if (locatorType.equals("name")) {
            return By.name(locatorValue);
        } else if (locatorType.equals("className")) {
            return By.className(locatorValue);
        } else {
            return By.xpath(locatorValue);
        }
    }

WebElement loginButton = this.element(this.by("loginButton" ));

//locatorType 就是定位方式;locatorValue 就是定位值

//配置文件内容为:
/*
loginButton=xpath>//*[@id='u1']/a[7]
*/

还有一个工具类

public class ProUtil {
    private Properties prop;
    private String filePath;

    public ProUtil(String filePath){
        this.filePath = filePath;
        this.prop = readProperties();
    }

    /**
     * 
     * 读取配置文件
     */

    private Properties readProperties(){
        Properties properties = new Properties();
        try 
        {
            InputStream inputStream = new FileInputStream(filePath);
            BufferedInputStream in = new BufferedInputStream(inputStream);
            properties.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return properties;
    }

    public String getPro(String key) throws Exception{

        //element.properties文件中,第一列为元素对象,第二列为定位方式By,第三列为定位的值
        if(prop.containsKey(key)){
            String valueElement = prop.getProperty(key);
            return valueElement;
        }else{
            System.out.println("你获取的key不对");
            return null;
        }

    }

}

其实,最好是做到代码分层:元素层,操作层,业务层。
这样,全部分开之后,真正在代码里基本看不到具体的定位方式,无论页面元素怎么换,定位方式怎么变,只需要修改配置文件即可。
有错,请指出! 互相学习

LitteBB 回复

学习,最近也在考虑通用性

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册