界面自动化脚本开发案例

Selenium介绍

1)框架底层使用JavaScript模拟真实用户对浏览器进行操作。测试脚本执行时,浏览器自动按照脚本代码做出点击,输入,打开,验证等操作,就像真实用户所做的一样,从终端用户的角度测试应用程序。
2)使浏览器兼容性测试自动化成为可能,尽管在不同的浏览器上依然有细微的差别。
3)使用简单,可使用Java,Python等多种语言编写用例脚本。

使用自动化脚本删除网站通知

delete_notices.gif

使用Actions工具模拟鼠标键盘事件

Actions里面的函数 作用
moveToElement 将鼠标移动到指定的元素
比如:action.moveToElement(target).perform();
sendKeys 往活动的元素里面输入内容
比如:action.sendKeys(Keys.ENTER).perform();
keyDown 按下修饰键(比如Ctrl,Alt,Shift等)
比如:action.keyDown(Keys.CONTROL).sendKeys(Keys.F5).perform();
keyUp 释放按键,比如:
action.keyDown(keys.CONTROL).sendKeys(Keys.F5).keyUp(Keys.CONTROL).perform();
dragAndDrop 模拟拖拽,比如:
action.dragAndDrop(element,target).perform();
doubleClick 双击鼠标,双击控件
clickAndHold 按住鼠标左键不放,按住控件不放
release 松开按键,释放按键

【参考】修饰键
https://www.beichengjiu.com/computerscience/339567.html

自动化代码如下:

package day06;

import java.util.List;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;

public class DeleteTest2 {

    public static void main(String[] args) throws Exception {
          //设置火狐浏览器执行文件的路径
          System.setProperty("WebDriver.firefox.bin", "C:\\Program Files\\Mozilla Firefox\\firefox.exe");
          WebDriver driver = new FirefoxDriver();
          driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);//隐性等待
          driver.get("http://192.168.0.124:8090/phpwind/index.php?m=u&c=login");//打开登录的页面
          driver.findElement(By.id("J_u_login_username")).sendKeys("OIXYOAMFan");//输入账号
          driver.findElement(By.id("J_u_login_password")).sendKeys("123456");//输入密码
          driver.findElement(By.className("btn_submit")).click();//点击登录
          Thread.sleep(3000);
          //请求通知列表页面
          driver.get("http://192.168.0.124:8090/phpwind/index.php?m=message&c=notice");
          //找到所有的通知框
          List<WebElement> boxes = driver.findElements(By.className("J_notice_item"));
          Actions action = new Actions(driver);
          //
          for(int i=0;i<boxes.size();i++) {
              //根据className查找方式找到第1个通知框
              WebElement  target= driver.findElement(By.className("J_notice_item"));
              action.moveToElement(target).perform();
              action.moveToElement(driver.findElement(By.linkText("删除"))).click().perform();
              action.moveToElement(driver.findElement(By.className("J_btn_ok"))).click().perform();
              Thread.sleep(2000);
          }
    }

}

使用自动化脚本发送弹幕

danmu2.gif

自动化代码如下:

package day06;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

public class DanmuTest {

    public static void main(String[] args) throws Exception{
          //设置火狐浏览器执行文件的路径
          System.setProperty("WebDriver.firefox.bin", "C:\\Program Files\\Mozilla Firefox\\firefox.exe");
          //
          WebDriver driver = new FirefoxDriver();
          //
          driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
          driver.get("https://www.acfun.cn/login");
          //
          driver.findElement(By.linkText("帐号登录")).click();
          //
          driver.findElement(By.id("ipt-account-login")).sendKeys("17721038951");
          driver.findElement(By.id("ipt-pwd-login")).sendKeys("123456");
          driver.findElement(By.className("btn-login")).click();
          Thread.sleep(3000);
          //
          driver.get("https://www.acfun.cn/v/ac10343293");
          for(int i=0;i<10;i++){
                driver.findElement(By.className("danmu-input")).sendKeys(System.currentTimeMillis()+"到此一游");
                driver.findElement(By.className("send-btn")).click();
                Thread.sleep(3000);
            }
    }

}

对注册功能进行自动化测试

register.gif

自动化代码如下:

package day06;

import java.util.Random;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class RegisterTest {
    private WebDriver driver;
    // 登录页面的请求地址
    private String url = "http://192.168.0.124:8090/phpwind/index.php?m=u&c=register";
    // 注销请求的地址
    private String logout_url = "http://192.168.0.124:8090/phpwind/index.php?m=u&c=login&a=logout";
    private By b1 = By.id("J_reg_username"); // 表示帐号输入框的查找方式
    private By b2 = By.id("J_reg_password"); // 表示密码输入框的查找方式
    private By b3 = By.id("J_reg_repassword");//表示确认密码的查找方式
    private By b4 = By.id("J_reg_email");//邮箱输入框的查找方式
    private By b5 = By.className("btn_submit");//表示注册按钮的查找方式

    @BeforeMethod
    public void logout() {
        driver.get(logout_url);// 注销
    }

    /**
     * 注册成功的测试用例
     * 
     * @param b6   表示注册成功提示框的查找方式
     * @param user 表示帐号
     * @param pwd  表示登录密码
     * @param pwd2
     * @param email
     * @param expected
     */
    @Test(dataProvider = "dp")
    public void register_success(By b6, String user, String pwd, String pwd2, String email, String expected) {
        driver.get(url);// 打开登录的页面
        driver.findElement(b1).sendKeys(user);// 输入账号
        driver.findElement(b2).sendKeys(pwd);// 输入密码
        driver.findElement(b3).sendKeys(pwd);// 输入确认密码
        driver.findElement(b4).sendKeys(email);// 输入邮箱
        driver.findElement(b5).click();// 点击注册
        Assert.assertTrue(driver.findElement(b6).getText().contains(expected));
    }

    /**
     * 注册失败的测试用例
     * 
     * @param b7       表示错误信息提示框的查找方式
     * @param user     表示帐号
     * @param pwd      表示登录密码
     * @param pwd2
     * @param email
     * @param expected 表示期望的内容
     */
    @Test(dataProvider = "dp2", enabled = true)
    public void register_fail(By b7, String user, String pwd, String pwd2, String email, String expected) throws Exception{
        driver.get(url);// 打开注册的页面
        driver.findElement(b1).sendKeys(user);// 输入账号
        driver.findElement(b2).sendKeys(pwd);
        driver.findElement(b3).sendKeys(pwd2);
        driver.findElement(b4).sendKeys(email);// 输入邮箱
        driver.findElement(b3).click();
        Thread.sleep(500);
        driver.findElement(b5).click();//
        Thread.sleep(500);
        Assert.assertTrue(driver.findElement(b7).getText().contains(expected));
    }

    /**
     * 注册成功的数据源
     * 
     * @return
     */
    @DataProvider
    public Object[][] dp() {
        return new Object[][] { new Object[] { By.xpath("/html/body/div/div[2]/div/div/h1"), getRandomString(10),
                "123456", "123456", getRandomString(10) + "@qq.com", "恭喜您" } };
    }

    /**
     * 注册失败的数据源
     * 
     * @return
     */
    @DataProvider
    public Object[][] dp2() {
        return new Object[][] {
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_username\"]/span"), "", "123456", "123456",
                        "155555@qq.com", "用户名不能为空" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_password\"]/span"), "ytre", "", "123456", "155555@qq.com",
                        "密码不能为空" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_repassword\"]/span"), "sdgd", "123456", "",
                        "155555@qq.com", "确认密码不能为空" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_email\"]/span"), "sdgd", "123456", "123456", "",
                        "邮箱不能为空" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_username\"]/span"), "asd1", "123456", "123456",
                        "155555@qq.com", "用户名已经存在" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_password\"]/span"), "sdgd", "123", "123456",
                        "155555@qq.com", "密码长度错误" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_repassword\"]/span"), "sdgd", "123456", "1234",
                        "155555@qq.com", "两次输入的密码不一致" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_email\"]/span"), "sdgd", "123456", "123456", "1555asd",
                        "请输入正确的电子邮箱地址" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_email\"]/span"), "sdgd", "123456", "123456",
                        "1506322725@qq.com", "该邮箱地址已经被注册" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_password\"]/span"), "sdgd", "1234567890123456", "123456",
                        "155555@qq.com", "密码长度错误" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_username\"]/span"), "sd", "123456", "123456",
                        "155555@qq.com", "用户名长度错误" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_username\"]/span"), "s  d", "123456", "123456",
                        "155555@qq.com", "用户名含有非法字符" },
                new Object[] { By.xpath("//*[@id=\"J_reg_tip_username\"]/span"), "qwertyuiasdghjkjg", "123456",
                        "123456", "155555@qq.com", "用户名长度错误" } };
    }

    @BeforeClass
    public void beforeClass() {
        // 设置火狐浏览器执行文件的路径
        System.setProperty("webdriver.firefox.bin", "C:\\Program Files\\Mozilla Firefox\\firefox.exe");
        //
        driver = new FirefoxDriver();
        // 设置最大等待时长
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        // 最大化窗口
        driver.manage().window().maximize();
    }

    @AfterClass
    public void afterClass() throws Exception {
        Thread.sleep(2000);
        // 关闭浏览器
        driver.quit();
    }

    /**
     * 生成随机字符串
     * 
     * @param length 表示随机字符串里面的字符个数
     * @return
     */
    public static String getRandomString(int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

}

日期控件的操作

12306.gif

自动化代码如下:

package examples;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.interactions.Actions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;

public class Test12306 {
    
    private WebDriver driver;
    
    @AfterClass
    public void end() throws Exception{
        Thread.sleep(2000);
        driver.quit();
    }
    
    @Test
    public void f() throws Exception{
          //设置火狐浏览器执行文件的路径
          //System.setProperty("WebDriver.firefox.bin", "C:\\Program Files\\Mozilla Firefox\\firefox.exe");
          //WebDriver driver = new FirefoxDriver();
          driver = new EdgeDriver();   
          Actions action = new Actions(driver);
          driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);//隐性等待
          driver.manage().window().setSize(new Dimension(1366, 1080));//设置浏览器窗口大小
          driver.get("https://www.12306.cn/index/");//打开页面
          action.moveToElement(driver.findElement(By.id("fromStationText"))).click().perform();
          Thread.sleep(500);
          driver.findElement(By.id("fromStationText")).clear();
          Thread.sleep(500);//显性等待
          driver.findElement(By.id("fromStationText")).sendKeys("sh");
          //
          driver.findElement(By.id("citem_0")).click();
          //
          driver.findElement(By.id("toStationText")).click();
          driver.findElement(By.id("toStationText")).clear();   
          driver.findElement(By.id("toStationText")).sendKeys("gz");
          Thread.sleep(500);//显性等待
          WebElement target = driver.findElement(By.id("citem_2"));//定位广州
          action.moveToElement(target).click().perform();//点击广州
          driver.findElement(By.id("isHighDan")).click();//勾选高铁
          driver.findElement(By.id("train_date")).click();
          Thread.sleep(1500);//显性等待,可以注释掉
          //driver.findElement(By.xpath("/html/body/div[11]/div[1]/div[2]/div[17]/div")).click();
          driver.findElement(By.cssSelector("div.cal:nth-child(1) > div:nth-child(3) > div:nth-child(18) > div:nth-child(1)")).click();
          Thread.sleep(1500);//显示等待,可以注释掉
          driver.findElement(By.id("search_one")).click();//点击查询
    }

}

使用自动化脚本上传头像

上传控件是file类型的input控件(非flash控件的情况)

driver.findElement(By.name("avatar")).sendKeys("d:\\123.jpg");
driver.findElement(By.id("J_avatgar_normal_btn")).click();

上传控件是flash控件的情况(swf文件里面的控件)

swf为上传头像的flash文件,该文件需要使用flash插件打开

image.png
image.png

方案1:
1)向flex工程注入SeleniumFlexAPI.swc,重新生成flash文件(swf文件)
2)自动化脚本里面引入user-extensions.js,然后通过调用js的接口来控制flash

方案2:
使用AutoIT(界面自动化工具)和Robot(键盘事件模拟)

方案3:
使用sikuli(图像识别工具)

//未完成

【参考】selenium自动化过程中如何操作Flash控件
https://www.cnblogs.com/hhudaqiang/p/6673012.html
【参考】js调用flash中定义的方法
http://www.phpvar.com/archives/2769.html
【参考】selenium对flex的支持
https://m.ancii.com/azmj5pu7l/
【参考】扩展Selenium对于Flash(Flex)元素识别和操作的实践小结
https://blog.csdn.net/wanglha/article/details/39135469

浏览器导航事件模拟(刷新、前进、后退)

Selenium代码如下:

driver.navigate().refresh();//刷新
driver.navigate().back();//后退
driver.navigate().forward();//前进

普通下拉框操作(select控件)

select控件的html代码如下:

<select name="bYear">
...
<option value="1997">1997年</option>
<option value="1996">1996年</option>
<option value="1995">1995年</option>
...
</select>

selenium代码如下:

WebElement target = driver.findElement(By.name("bYear"));
//创建一个选择器
Select select = new Select(target);
//选择1996
//select.selectByVisibleText("1996年");
//select.selectByIndex(24);
select.selectByValue("1996");

确认对话框操作(确认和取消)

1)通过js实现的弹窗(使用confirm函数或者alert函数实现的弹窗)

//切换到弹窗
Alert dialog = driver.switchTo().alert();
//dialog.accept();//确定
dialog.dismiss();//取消
dialog.getText();//获取提示框里面的提示信息

2)使用div实现的提示框怎么操作

driver.findElement(By.linkText("删除")).click();
//点击确定
driver.findElement(By.className("J_btn_ok")).click();

框架切换

1)先切到默认的html文档

//回到默认的html文档
driver.switchTo().defaultContent();

2)然后切到目标框架(指定的框架)

//切换到框架
driver.switchTo().frame(driver.findElement(By.id("login_frame")));

切换到新打开的窗口

//切换到指定的窗口(目标窗口)
for(String handle:driver.getWindowHandles()) {
      driver.switchTo().window(handle);
      System.out.println(driver.getTitle());//打印窗口的标题
      if(driver.getTitle().contains("登录")) {
          break;
    }
}

远程驱动各种主流浏览器

//获取ie浏览器的配置工具
InternetExplorerOptions options = new InternetExplorerOptions();
//配置浏览器的名称
options.setCapability("browser.name", "internet explorer");
//设置浏览器的版本
options.setCapability("platform", Platform.WINDOWS);
//解决ie浏览器输入文本很慢的问题
options.requireWindowFocus();
//连接hub
driver = new RemoteWebDriver(new URL("http://192.168.0.124:4444/wd/hub"), options);
...

//获取chrome浏览器的配置工具
ChromeOptions options = new ChromeOptions();
//配置浏览器的名称
options.setCapability("browser.name", "chrome");
//设置浏览器的版本
options.setCapability("platform", Platform.WINDOWS);
//连接hub
driver = new RemoteWebDriver(new URL("http://192.168.0.124:4444/wd/hub"), options);
...

//获取firefox浏览器的配置工具
FirefoxOptions options options = new FirefoxOptions();
//配置浏览器的名称
options.setCapability("browser.name", "firefox");
//设置浏览器的版本
options.setCapability("platform", Platform.WINDOWS);
//连接hub
driver = new RemoteWebDriver(new URL("http://192.168.0.124:4444/wd/hub"), options);

Selenium API文档(Java版使用说明书)

https://seleniumhq.github.io/selenium/docs/api/java/index.html?index-all.html

微信扫一扫关注该公众号【测试开发者部落】

image.png

点击链接加入群聊【软件测试学习交流群】
https://jq.qq.com/?_wv=1027&k=5eVEhfN
软件测试学习交流QQ群号:511619105

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容

  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,498评论 1 11
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,105评论 1 32
  • 第一站 上海迪士尼 每逢假日就是朋友圈晒旅行照的日子,每次都羡慕不已,常常此时会默默在心里对自己说下次我也一定要出...
    大海之音阅读 393评论 0 0
  • 如果把学习的目的定义为只是为了做对的事情,而不是希望学习之后获得某种喜人的成果。那么学习本身将变得容易得多。 投资...
    若谷笔记阅读 216评论 0 0
  • 夜晚的天空像黑绸带一样,小唐伸长胳膊,用小刀在绸带上轻轻画了一条线,然后用手,轻轻地掀开那条线。哇,金色光芒便喷洒...
    元元阅读 234评论 0 0