WebUI自动化知识点总结-基于Java语言

一:Selenium简介

Selenium用于Web应用程序测试的工具,开源并且免费的,覆盖IE、Chrome、FireFox、Safari等主流浏览器,通过在不同浏览器中运行自动化测试。支持Java、Python、Net、Perl等编程语言进行自动化测试脚本编写。

Selenium家族:

  • Selenium IDE,Firefox/Chrome浏览器的扩展插件,通过Selenium IDE我们可以录制和回放浏览器操作,快速实现自动化测试,功能很鸡肋,很难扩展自定义功能,一般很少用。
  • Selenium WebDriver,Selenium的核心,提供了各种语言环境的API来支持更多控制权和编写符合标准软件开发实践的应用程序。
  • Selenium Grid,分布式测试,通过Selenium Grid可以将自动化测试脚本分发到不同的测试机器中执行。

 

二:驱动的使用:

1、浏览器驱动下载地址:

 
 

2、设置驱动文件路径:

(1)Chrome驱动:System.setProperty("webdriver.chrome.driver","驱动路径")
(2)Firefox驱动:System.setProperty("webdriver.firefox.driver","驱动路径")
(3)IE驱动:IE驱动受到的限制比较多,一般需要3个步骤即可解决常见的报错问题,少一步都可能会报错:1、取消IE安全设置 2、忽略浏览器缩放设置 3、设置驱动路径
DesiredCapabilities capabilities = new DesiredCapabilities();
//取消IE安全设置(忽略IE的Protected Mode的设置)
capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
//忽略浏览器缩放设置
capabilities.setCapability(InternetExplorerDriver.IGNORE_ZOOM_SETTING, true);
System.setProperty("webdriver.ie.driver", "src\\test\\resources\\IEDriverServer.exe");
WebDriver webDriver = new InternetExplorerDriver(capabilities);
 

 3、驱动的执行原理: 

 
 

三:元素定位

有八大元素定位方式:id、name、tagName、className、linkText、 partialLinkText 、 cssSelector 、 xpath 
 

1、ID定位

如果页面存在ID唯一定位到的元素,可以优先考虑使用id定位,如:百度的输入框定位:By.id("kw")

 

2、name定位

根据元素的name属性定位。如上述百度输入框可以使用name定位:By.name("wd")

3、tagName定位:

根据元素的标签名定位。该定位元素很少使用,因为页面中可能会存在很多相同标签名的元素,这时候就无法唯一定位到自己想要操作的元素,比如上述百度输入框的元素标签是input标签,由于页面存在很多input元素,所以无法唯一定位到我们想要的元素

4、className定位

根据样式名定位。如果元素存在class属性,根据class属性可以唯一定位到该元素可以考虑使用该种定位方式:如上述百度输入框可以使用className定位:By.className("s_ipt")

5、linkText定位

根据超链接完整文本定位。该定位方式只用于定位超链接标签元素,比如:百度页面的“新闻”超链接可以使用该种定位方式:By.linkText("新闻")

6、partialLinkText 定位

超链接部分文本匹配定位。该定位方式也是只能用于定位超链接标签的元素,由于某些链接的文本很长,我们可以取代表性文本唯一定位,如:百度页面的"hao123"超链接可以使用该种定位方式:By.partialLinkText("hao")

7、cssSelector定位

根据CSS选择器定位,若用id定位,则用 #。若用class定位,则用.
该种定位方式有六种,以下用百度输入框举例:
(1)根据元素id定位:By.cssSelector("#kw")
(2)根据元素class定位:By.cssSelector(".s_ipt")
(3)根据元素标签名定位:跟上述的tagName定位类似,由于页面可能会存在很多相同名字标签,无法做到唯一定位,一般都不用该方式
(4)根据元素单属性定位:By.cssSelector("input[id='kw']"),By.cssSelector("input[name='wd']"),By.cssSelector("input[class='s_ipt']")
(5)根据元素多属性定位:By.cssSelector("input[id='kw'][name='wd']")
(6)根据元素层级定位:格式:父标签[父标签属性名=父标签属性值]>子标签,如此处的百度输入框定位可以写成:By.cssSelector("span[class='bg s_ipt_wr new-pmd quickdelete-wrap']>input")

8、XPATH定位

本文最为喜欢使用的定位方式,可以解决绝大部分的元素定位,特别推荐使用。XPATH有绝对定位、相对定位、轴定位三大种。
(1)绝对定位:根据页面的根元素开始,一直不断取到自己想定位的元素,如果不是万分无奈,都不要用此种定位方式,因为页面中如果某个元素发生了变化,定位表达式可能就会失效,而且很难排查是哪个元素发生了改变。
(2)相对定位:非常推荐使用。以//表示从页面的任意指定符合的元素节点开始进行解析,而/表示直接的下级元素,*表示通配任意的元素。使用方式:
(2.1)根据属性定位:By.xpath("//标签名[@属性名='属性值']"),如:百度输入框:By.xpath("//input[@id='kw']"),By.xpath("//*[@id='kw']")
(2.2)根据多个属性定位:By.xpath("//标签名[@属性名1='属性值1'][@属性名2='属性值2'][@属性名3='属性值3']")
(2.3)根据文本定位:By.xpath("//标签名(text()='值')"),如:百度页面的新闻:By.xpath("//a[text()='新闻']"),By.xpath("//*[text()='新闻']")
(2.4)根据属性值模糊匹配:By.xpath("//标签名[contains(@属性名,'值')]"),  如百度页面的新闻:By.xpath("//a[contains(@href,'news.baidu')]")
(2.5)根据文本值模糊匹配:By.xpath("//标签名[contains(text(),'值')]),如百度页面的hao123:By.xpath("//a[contains(text(),'hao123')]")
(2.6)根据层级关系定位:使用场景:页面元素可能无法通过常规定位方法定位,可以考虑父元素或者祖先元素是否有可以唯一定位的元素,通过该唯一定位元素再去定位我们想要的元素。
  (2.6.1)定位直接父元素再定位我们想要的元素://*[@id='父元素唯一id']/child
  (2.6.2)定位祖先元素再定位我们想要的元素://*[@id='祖先元素唯一id']//child
(3)轴定位:相当于Xpath的必杀器了,基本可以解决95%的定位元素疑难杂症,上面所有的定位方式都无法定位元素的时候,可以考虑使用该定位。
轴名称 释义
ancestor 选取当前节点的所有祖先节点(包括父节点)
parent 选取当前节点的父节点
preceding 选取当前节点之前的所有节点
preceding-sibling 选取当前节点之前的所有兄弟节点
following 选取当前节点之后的所有节点
following-sibling 选取当前节点之后的所有兄弟节点

使用方式:轴名称::标签名

示例:取百度搜索框的父元素span标签元素: //input[@id='kw']//parent::span

取百度搜索框之前的兄弟元素span标签元素://input[@id='kw']//preceding::span[@class='soutu-btn']

 

四:selenium常用操作 API

1、元素对象常用API

首先先有元素对象:Webelement element=driver.findElement(By by);其中by是元素定位信息

(1.1)、点击操作:element.click();

(1.2)、输入内容:element.sendKeys("str");

(1.3)、清除内容:element.clear();

(1.4)、键盘操作:

(1.4.1)element.sendKeys(Keys.CONTROL,"a");//ctrl+a 全选
(1.4.2)element.sendKeys(Keys.CONTROL,"x");//ctrl+x 剪切
(1.4.3)element.sendKeys(Keys.CONTROL,"c");//ctrl+c 复制
(1.4.4)element.sendKeys(Keys.CONTROL,"v");//ctrl+v 粘贴
(1.4.5)element.sendKeys(Keys.ENTER);//回车
(1.4.6)element.sendKeys(Keys.BACK_SPACE);//删除
(1.4.7)element.sendKeys(Keys.SPACE);//空格键

(1.5)、获取元素标签名:element.getTagName();

(1.6)、获取元素属性:element.getAttribute();

(1.7)、获取元素文本值:element.getText();

2、driver对象常用API

(2.1)、访问指定url:driver.get("url")

(2.2)、获取当前页面url:driver.getCurrentUrl();

(2.3)、获取当前页面标题:driver.getTittle();

(2.4)、获取当前页面源码:driver.getPageSource();

(2.5)、关闭driver当前所在窗口:driver.close();

(2.6)、关闭driver对象以及所有窗口:driver.quit()

(2.7)、窗口操作:
首先先获取window对象:Window window = driver.manage().window();
(2.7.1)、窗口最大化:window.maximize();
(2.7.2)、浏览器全屏:window.fullscreen();
(2.7.3)、获取窗口位置:window.getPosition();
(2.7.4)、获取窗口大小:window.getSize();
(2.7.5)、设置窗口位置:window.setPosition(targetPosition)
(2.7.6)、设置窗口大小:window.setSize(targetSize);
(2.8)、截屏操作:需要导入依赖包:Commons IO
File file=driver.getScreenshotAs(OutputType FILE);
try{
    FileUtils.copyFile(file,new File("E:\\projectDir"));
}catch(IOException e){
e.printStackTrace();
}
 
 

五:三种等待:硬等待、隐式等待、显式等待

1、硬等待:Thread.sleep(long millis)

特点:强制线程等待

优点:使用简单

缺点:容易造成时间浪费,建议少用

2、隐式等待:driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

特点:在设置的超时时间范围内不断查找元素,直到找到元素或者超时为止

优点:只需要设置一次,在 WebDriver 实例的整个生命周期都是生效的

缺点:只能找到元素,不能适用条件更复杂的情况,如:元素可点击、元素可见、元素的属性发生变化等。

3、显示等待:

特点:可以灵活指定等待到元素满足某个条件为止,最常用

优点:基本可以满足所有元素等待条件,使得自动化脚本更加稳定

缺点:暂无缺点

使用方法:先创建一个WebDriverWait对象: WebDriverWait webDriverwait=new WebDriverWait(); 

//等待元素可点击

webDriverWait.until(ExpectedConditions.elementToBeClickable(By));

//等待元素可见,光是找到元素不行,必须得能被看到

webDriverWait.until(ExpectedConditions.visibilityOfElementLocated(By));

//等待元素找到

webDriverWait.until(ExpectedConditions.presenceOfElementLocated(By));

//等待所有元素可见

webDriverWait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By));

(1)封装等待元素可见方法:

/**
 * 显式等待元素可见二次封装
 * @param driver 驱动对象
 * @param by 元素定位信息
 */
public WebElement waitElementVisible(RemoteWebDriver driver, By by ){
    WebElement webElement = null;
    try {
        //1、实例化WebDriverWait 超时时间10s
        WebDriverWait webDriverWait = new WebDriverWait(driver,10);
        //2、通过until方法等到某个条件满足时为止
        webElement = webDriverWait.until(ExpectedConditions.visibilityOfElementLocated(by));
    }catch (Exception e){
        e.printStackTrace();
    }

    return webElement;
}

(2)封装元素可被点击方法:

/**
 * 显式等待元素可被点击二次封装
 * @param driver 驱动对象
 * @param by 元素定位信息
 */
public WebElement waitElementClickable(RemoteWebDriver driver, By by ){
    WebElement webElement =null;
    try {
        //1、实例化WebDriverWait 超时时间10s
        WebDriverWait webDriverWait = new WebDriverWait(driver, 10);
        //2、通过until方法等到某个条件满足时为止
        webElement = webDriverWait.until(ExpectedConditions.elementToBeClickable(by));
    }catch (Exception e){
        e.printStackTrace();
    }
    return webElement;
}

 

六:三种切换

1、切换windows

当我们点击a标签元素时,如果a标签有target="_blank"时,就会打开一个新的窗口,这时候我们如果想要操作新窗口的元素,需要切换windows。

/**
 * 封装的通用切换窗口的方法-根据对应窗口的标题来切换
 * @param title 窗口标题
 */
public void switchWindowWithTitle(String title){
    Set<String> allWindowHandles = driver.getWindowHandles();
    for (String windowHandle: allWindowHandles){
        //根据窗口的标题来进行判断
        if(title.equals(driver.getTitle())){
            break;
        }else {
            logger.info("切换到标题为:【"+title+"】的窗口");
            driver.switchTo().window(windowHandle);
        }
    }
}

/**
 * 封装的通用切换窗口的方法-根据对应窗口的url来切换
 * @param url 窗口url
 */
public void switchWindowWithURL(String url){
    Set<String> allWindowHandles = driver.getWindowHandles();
    for (String windowHandle: allWindowHandles){
        //根据窗口的URL来进行判断
        if (url.equals(driver.getCurrentUrl())){
            break;
        }else {
            logger.info("切换到url为:【"+url+"】的窗口");
            driver.switchTo().window(windowHandle);
        }
    }
}

2、切换Iframe

当想要定位iframe中的元素时,我们需要切换Iframe,否则无法定位Iframe里的元素

/**
 * 切换到指定IFrame封装
 * @param driver 驱动对象
 * @param by 元素定位信息
 * @param frameInfo 自定义frame信息
 */
public void switchFrame(RemoteWebDriver driver,By by,String frameInfo){
    WebElement element = waitElementVisible(driver, by);
    logger.info("切换IFrame:"+frameInfo);
    driver.switchTo().frame(element);
}

/**
 * 从IFrame中切换到默认页面封装
 * @param driver 驱动对象
 */
public void switchDefaultFrame(RemoteWebDriver driver){
    logger.info("切换回默认的页面");
    driver.switchTo().defaultContent();
}

3、切换Alert弹窗

有些时候,由浏览器弹出一个Alert提示框,如果我们不去处理,无法进行下一步操作。

/**
 * Alert弹窗切换
 * @param driver 驱动对象
 */
public void switchAlert(RemoteWebDriver driver){
    logger.info("切换到alert窗口");
    Alert alert = driver.switchTo().alert();
    // alert.accept();  //点击确定
    //alert.dismiss(); //点击取消
    alert.getText();  //获取弹窗文本
}

 

七:特殊元素操作

1、JavaScript操作

某些特殊情况下,使用selenium的api无法操作页面元素,或者运行的时候报元素无法被点击等异常错误时,这时候可以考虑通过JavaScript操作是否能解决问题。

使用方式:

(1)不传参方式:

driver.executeScript("JS代码");

(2)传参方式:

WebElement element = driver.findElement(By.id("xx"));
driver.executeScript("arguments[0].click();",element);

使用场景:(1)设置/去除元素属性:setAttribute()/removeAttribute(),这里以12306网站为例:

driver.get("https://www.12306.cn/index/");
Thread.sleep(2000);
//设置元素的属性值
driver.executeScript("document.getElementById('train_date').setAttribute('value','2020-1-1');");
//移除掉元素的属性值
driver.executeScript("document.getElementById('train_date').removeAttribute('value');");

 (2)页面滚动

实例1:12306网站操作:

driver.get("https://www.12306.cn/index/");
Thread.sleep(2000);
//滚动到页面底部
//driver.executeScript("window.scrollTo(0, document.body.scrollHeight);");
//2-2、滚动到指定的元素上去
driver.executeScript("document.getElementById('index_ads').scrollIntoViewIfNeeded(true);");

实例2:在豌豆荚软件排行页面"https://www.wandoujia.com/top/app"不断地滚动对【虎牙直播】元素点击。

ublic class UITest04 {

    public static void main(String[] args) throws InterruptedException {
        RemoteWebDriver driver = getDriver("chrome");
        driver.get("https://www.wandoujia.com/top/app");
        driver.manage().window().maximize();
        Thread.sleep(1000);

        while (true){
            if (driver.getPageSource().contains("title=\"虎牙直播\"")) {
                driver.findElementByXPath("//a[text()='虎牙直播']").click();
                break;
            }else {
                //点击查看更多
                WebElement loadMore = waitElementVisible(driver, By.xpath("//div[@class='load-more']/a"));
                //判断【查看更多】是否已经加载完,如果加载完,则跳出循环
                if (loadMore.getAttribute("style").equals("display: none;")){
                    break;
                }
                driver.executeScript("arguments[0].scrollIntoViewIfNeeded(true);", loadMore);
                loadMore.click();
                Thread.sleep(1000);

            }
        }
        Thread.sleep(1000);
        driver.quit();
    }



    /**
     * 封装的通用切换窗口的方法-根据对应窗口的标题来切换
     * @param driver 驱动对象
     * @param title 窗口标题
     */
    public static void switchWindow(WebDriver driver, String title)  {
        Set<String> allWindowHandles = driver.getWindowHandles();
        for (String windowHandle: allWindowHandles){
            //根据窗口的URL地址或者标题来进行判断
            if(title.equals(driver.getTitle())){
                break;
            }else {
                driver.switchTo().window(windowHandle);
            }
        }
    }

    /**
     * 显式等待元素可见二次封装
     * @param driver
     * @param by
     */
    public static WebElement waitElementVisible(WebDriver driver, By by ){
        //1、实例化WebDriverWait 超时时间10s
        WebDriverWait webDriverWait = new WebDriverWait(driver,10);
        //2、通过until方法等到某个条件满足时为止
        WebElement webElement = webDriverWait.until(ExpectedConditions.visibilityOfElementLocated(by));
        return webElement;
    }

    /**
     * 显式等待元素可被点击二次封装
     * @param driver
     * @param by
     */
    public static WebElement waitElementClickable(WebDriver driver, By by ){
        //1、实例化WebDriverWait 超时时间10s
        WebDriverWait webDriverWait = new WebDriverWait(driver,10);
        //2、通过until方法等到某个条件满足时为止
        WebElement webElement = webDriverWait.until(ExpectedConditions.elementToBeClickable(by));
        return webElement;
    }


    /**
     * 打开所有浏览器封装
     * @param type  浏览器类型
     * @return
     */
    public static RemoteWebDriver getDriver(String type){
        RemoteWebDriver driver = null;
        if("chrome".equals(type)){
            //1、加载浏览器驱动
            System.setProperty("webdriver.chrome.driver","src/test/resources/chromedriver.exe");
            //2、创建ChromeDriver对象
            driver =new ChromeDriver();
        }else if ("firefox".equals(type)){
            //加载浏览器驱动
            System.setProperty("webdriver.gecko.driver","src/test/resources/geckodriver.exe");
            //如果firefox不是默认路径,配置firefox路径
            System.setProperty("webdriver.firefox.bin","D:\\Program Files\\Mozilla Firefox\\firefox.exe");
            driver=new FirefoxDriver();
        }else if ("ie".equals(type)){
            //加载浏览器驱动
            System.setProperty("webdriver.ie.driver","src/test/resources/IEDriverServer.exe");
            //IE浏览器默认会有125%的缩放和安全设置,需要禁用,不然会报错
            DesiredCapabilities capabilities=new DesiredCapabilities();
            capabilities.setCapability(InternetExplorerDriver.IGNORE_ZOOM_SETTING,true);  //忽略浏览器缩放比例
            capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS,true);//忽略IE浏览器的安全模式
            //创建IEDriver
            driver=new InternetExplorerDriver();
        }else {
            System.out.println("浏览器传值有误");
        }
        return driver;

    }
}

(3)执行的时候,控制台报错如下:Element is not clickable at point,Other element would receive the click ,或者其他奇形怪状的错误的时候,都可以考虑使用JavaScript操作尝试下是否能解决错误。

 

2、鼠标操作

自动化有些场景是需要鼠标配合使用的时候,可以使用Selenium的Actions类来模拟鼠标操作,通过Actions对象可以发起鼠标左键、右键、移动鼠标等操作,最后使用perform方法执行操作。

clickAndHold(element)  //在特定元素上单击鼠标左键(不释放)
release(element)       //在特定元素上释放鼠标左键
doubleClick(element)   //在特定元素上双击鼠标左键
moveToElement(element) //移动鼠标指针到特定元素
contextClick(element)  //在特定元素上右键单击
dragAndDrop(element)   //拖拽元素
perform()       //执行具体的操作,前面6个方法都是声明一个操作,只有调用perform()后才会真正执行操作

使用方式:

Actions actions = new Actions(driver);
WebElement webElement1 = driver.findElement(By.id("XX"));
WebElement webElement2 = driver.findElement(By.id("XX"));
 //按住-->拖拽-->鼠标释放
actions.clickAndHold(webElement1).moveToElement(webElement2).release().perform();
//双击
actions.doubleClick(webElement1).perform();

3、文件上传操作

参考:http://testingpai.com/article/1595507303689

4:验证码操作

(1)、与开发沟通在测试环境去除验证码

(2)、在测试环境开个万能验证码,推荐使用

(3)、使用自动识别技术破解验证码,时间充裕可以尝试

(4)、通过读取Redis缓存,绕过验证码。

 

posted @ 2021-12-28 00:07  筱筱创  阅读(562)  评论(0编辑  收藏  举报