• 自动化测试--8种定位方式以及等待详解


    1.id--标签中id 的值

    如果开发人员编程规范,页面的元素id 不重复的且不是动态生成的id时,使用id 定位非常容易。

    //<select style=" 33%" id="CityCode" name="CityCode" class="form-control lopicker">
    //使用id定位元素
    WebElement element =  driver.findElement(By.id("CityCode"));

    2.name--标签中name的值

    //<select style=" 33%" id="CityCode" name="CityCode" class="form-control lopicker">

    //使用name定位元素
    WebElement cityelement = driver.findElement(By.name("CityCode"));

    3.className--标签中class属性的值

     //<select style=" 33%" id="ProvinceCode" name="ProvinceCode" class="form-control lopicker">
    //使用className定位
    WebElement element = driver.findElement(By.className("form-control"));

    4.tagName--标签名

    //<select style=" 33%" id="ProvinceCode" name="ProvinceCode" class="form-control lopicker">
    //使用标签名定位元素
    WebElement element = driver.findElement(By.tagName("select"));

    5.linkText--a标签中全部的文本值

    //<a href="/Competition/Detail/c05a5ae3-32c6-4b81-b042-646ad8de275a" title="寻宝机器人赛" class="link item_title">寻宝机器人赛</a>
        WebElement comElement = driver.findElement(By.linkText("寻宝机器人赛"));

    6.partialLinkText--a标签中部分的文本值

    //<a href="/Competition/Detail/c05a5ae3-32c6-4b81-b042-646ad8de275a" title="寻宝机器人赛" class="link item_title">寻宝机器人赛</a>
         WebElement comElement = driver.findElement(By.partialLinkText("寻宝"));

    7.CSSSelector--css选择器(非常重要)

     //<select style=" 33%" id="ProvinceCode" name="ProvinceCode" class="form-control lopicker">
         WebElement element = driver.findElement(By.cssSelector(".form-control"));
            WebElement element1= driver.findElement(By.cssSelector("select.form-control"));
      /**
           * (有属性的标签)非常常用CssSelector:标签名[属性名='属性值'][属性名='属性值'][属性名='属性值'][属性名='属性值']
           */
         //<select style=" 33%" id="CityCode" name="CityCode" class="form-control lopicker">
        WebElement cityelement = driver.findElement(By.cssSelector("select#CityCode"));
        WebElement cityelement1 = driver.findElement(By.cssSelector("#CityCode"));
        WebElement cityelement2 = driver.findElement(By.cssSelector("select[name='CityCode']"));
        WebElement cityelement3 = driver.findElement(By.cssSelector("select[class='form-control lopicker'][name='CityCode']"));

    8.xpath--相对路径/绝对路径

    使用chrome自带或者火狐的xpath的插件可以获得元素的相对或者绝对路径。

    chrome:

    fireFox:

         //<select style=" 33%" id="AreaCode" name="AreaCode" class="form-control lopicker">
         //通过单个属性定位
         WebElement areaElement = driver.findElement(By.xpath("//*[@id="AreaCode"]"));
         //通过多个属性定位
         WebElement areaElement1 = driver.findElement(By.xpath("//select[@style=' 33%' and @name='AreaCode']"));
        //<a href="/Competition/Detail/c05a5ae3-32c6-4b81-b042-646ad8de275a" title="寻宝机器人赛" class="link item_title">寻宝机器人赛</a>
         //通过contains表达式
         WebElement comElement1 = driver.findElement(By.xpath("//a[@class='link item_title' and contains(text(),'机器人赛')]"));
         //通过startsWith表达式
         WebElement comElement2 = driver.findElement(By.xpath("//a[@class='link item_title' and starts-with(text(),'寻宝')]"));
         //如果读者的谷歌版本只支持xpath1.0,所以ends-with不能使用
        // WebElement comElement3 = driver.findElement(By.xpath("//a[@class='link item_title' and ends-with(text(),'机器人赛')]"));
         //如果ends-with不支持,可以使用下面方式代替
         WebElement comElement4 = driver.findElement(By.xpath("//a[substring(text(), string-length(text()) - string-length('人赛') +1) = '人赛']"));

    上面总结了8种定位元素的方法。

    下面说明一些特殊情况:

    1.id是动态生成的。

    这种情况下,可以选择其他的定位方式。如cssSelector xPath等

    如,生成的id总是以register字符串结尾:

    <input id="m.f0.menu.f2.volumeTabs.BLOCK_COMMON.tcw.form.register" name="m.f0.menu.f2.volumeTabs.BLOCK_COMMON.tcw.form.register" class="aranea-checkbox" type="checkbox"> </td>

    此时,可以通过xpath的方式来查找

    driver.findElement(By.xpath("//input[ends-with(@id,'register')]"));

    如果这个动态id有规律可循的话,也可以通过id来定位元素。具体就不举例了。

    2.可以将查找元素封装成相应的方法,直接调用。方便添加日志信息。

        /**
         * 查找元素的方法 element
         */
        public WebElement findElementBy(By by) {
            return driver.findElement(by);
        }
    
        /**
         * 查找多个元素的方法 elements
         */
        public List<WebElement> findElementsBy(By by) {
            return driver.findElements(by);
        }
    
        /**
         * 查找到多个元素后,继续向下查找(定位出一个元素这是一堆相同的elements中 选择 其中方的 一个 然后在这个选定的中 继续定位
      */
    public WebElement getOneElement(By bys, By by, int index) {
        return findElementsBy(bys).get(index).findElement(by);
    }

    3.在查找元素的时候,会考虑到该元素资源是否已经加载完成。

    下面给大家总结一下,关于自动化测试中的“等待”:

    1.硬性等待---封装成方法,方便调用。

    /**
    * 硬性等待,等待时间为:sleepTime。
    */
    public void Wait(int sleepTime) {
    if (sleepTime <= 0) {
    return;
    }
    try {
    Thread.sleep(sleepTime);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }

    2.隐式等待---这个等待是全局的,是针对当前driver的。一旦设置之后,只要该driver执行findElement或者findElements方法,首先回去找元素,如果没找到,会在设置的时间内一直轮询查找,直到timeOut.由于是全局性的,有些元素不需要等待,所以会造成时间的浪费。因为浏览器是自上而下渲染的,如果元素1在元素2的上面,当你第一次查找过元素2,之后再查找元素1的时候,是不需要等待的。但是设置了该全局参数之后,还是会去等待。

    driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

    3.显示等待(推荐使用)

    /**
         * 对外提供智能等待 查找元素的方法
         * @param driver
         * @param time
         * 元素的超时等待时间
         * @param by
         * @return
         */
        public static WebElement waitElement(WebDriver driver,int time,By by) {
            WebElement element=null;
            
            WebDriverWait wait = new WebDriverWait(driver, time);
            
            try {
                element = wait.until(new ExpectedCondition<WebElement>() {
    
                    public WebElement apply(WebDriver driver) {
                        WebElement element = driver.findElement(by);
                        return element;
                    }
                });
            } catch (TimeoutException e) {
                System.out.println("元素"+by.toString()+" "+time+"S内未能找到");
                logger.info("元素未找到");
            }
            
            
            return element;
            
        }
        
        /**
         * 对外提供智能等待 查找元素的方法,固定的等待超时时间为5S
         * @param by
         * @return
         */
        public static WebElement waitElement(By by) {
            
            WebDriver driver= GetDriverUtil.getDriver();
            return waitElement(driver, 5, by);
            /*WebElement element = null;
            try {
                element = (new WebDriverWait(driver, 5)).until(new ExpectedCondition<WebElement>() {
    
                    @Override
                    public WebElement apply(WebDriver driver) {
                        
                        return driver.findElement(by);
                    }
    
                
                });
            } catch (Exception e) {
                System.out.println("元素"+by.toString()+" "+"5S内未能找到");
                e.printStackTrace();
            }
            
            return element;*/
        }

     上面的ExpectedCondition是我们自己编写的,实际上,在selenium的ExpectedConditions类中,已经封装了各种元素等待条件。有兴趣可以去了解下

    可以去看一下源码,内部也是使用的匿名内部类new ExpectedCondition{},下面是拿出一个来举例:

    判断一个元素是否可点击:

    1.该元素在dom中存在

    2.该元素可见

    3.该元素为enabled

      /**
       * An expectation for checking an element is visible and enabled such that you can click it.
       *
       * @param locator used to find the element
       * @return the WebElement once it is located and clickable (visible and enabled)
       */
      public static ExpectedCondition<WebElement> elementToBeClickable(final By locator) {
    //匿名内部类
    return new ExpectedCondition<WebElement>() { @Override public WebElement apply(WebDriver driver) {
    //判断元素是否可见 WebElement element
    = visibilityOfElementLocated(locator).apply(driver); try {
    //如果元素可见并且元素生效的话则返回元素
    if (element != null && element.isEnabled()) { return element; } return null; } catch (StaleElementReferenceException e) { return null; } } @Override public String toString() { return "element to be clickable: " + locator; } }; }

    上面总结的是元素的等待,自动化测试用,还有:等待页面加载的超时时间测试

    a.等待页面加载,设置超时时间。超时之后,不再等待,直接去定位某元素。(需要执行js脚本)

        /**
         *等待页面加载,设置页面加载的超时时间,如果规定时间内还未加载完成,则停止加载,并定位指定元素
         * @param driver
         * @param timeout
         * @param by
         */
        
        public static void pageLoad(WebDriver driver,int timeout,String url) {
            try {
                //设置页面加载超时时间
                driver.manage().timeouts().pageLoadTimeout(timeout, TimeUnit.SECONDS);
                driver.get(url);
            } catch (Exception e) {
                ((JavascriptExecutor)driver).executeScript("window.stop()");
            }
            
            driver.findElement(By.id("user[login]")).sendKeys("feifeifei");
            
        }
        

    b.有时加载页面超时,需要刷新一次,并输出页面的加载状态。(需要执行js脚本)

    /***
         * 启动浏览器并打开页面
         */
        public void launchBrowser(String webUrl, int timeOut) {
            //getDriver()就是上一篇博客中讲的 封装获取driver的方法
            driver = GetDriverUtil.getDriver();
            try {
                //最大化浏览器窗口(已经封装成方法)
                maxWindow();
                //设置等待页面加载的时间(已经封装成方法)
                waitForPageLoading(timeOut);
                //打开浏览器指定页面(已经封装成方法)
                get(webUrl);
            } catch (TimeoutException e) {
                logger.warn("页面没有完全加载出来,刷新重试");
                //刷新页面
                refresh();
                //创建js脚本执行器
                JavascriptExecutor js = (JavascriptExecutor) driver;
                //执行脚本,描述了文档的加载状态. 状态分为
                //loading document 仍在加载
                //interactive / 互动    文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载
                //complete / 完成   T文档和所有子资源已完成加载。状态表示 load 事件即将被触发。
                
                String status = (String) js.executeScript("return document.readyState");
                //将返回的状态通过日志打印出来
                logger.info("打印状态:" + status);
            }
    
        }
        在自动化测试过程中,还经常遇到异步请求的情况,如下图:


    当需要进行异步请求元素的定位时,则需要等待异步脚本执行完成并返回结果。这时需要设置异步脚本的超时时间。
    /** setScriptTimeout。异步脚本的超时时间。(封装成方法,方便调用)webdriver可以异步执行脚本,这个是设置异步执行脚本脚本返回结果的超时时间 */
        public void setScriptTimeout(int timeOut) {
            driver.manage().timeouts().setScriptTimeout(timeOut, TimeUnit.SECONDS);
        }
    
    
    
    以上,详细介绍了硬性等待、隐式等待、只能等待、页面加载超时、异步脚本超时的常用方法。希望给大家带来帮助。
  • 相关阅读:
    POJ 1436 Horizontally Visible Segments (线段树+区间覆盖)
    HDU 4671 Backup Plan (构造)
    POJ 3325 Help with Intervals (线段树(难))
    HDU 4649 Professor Tian (位运算 + 按位DP)
    HDU 4662 MU Puzzle (YY+枚举)
    HDU 4638 Group (线段树 + 离线)
    深入浅出Node.js (附录A)
    JS的变量声明和函数声明提升
    JS基础:翻转数组
    JS基础:求一组数中的最大最小值,以及所在位置
  • 原文地址:https://www.cnblogs.com/clairejing/p/9466993.html
Copyright © 2020-2023  润新知