自动化测试selenium在小公司的成功实践 前言 背景

1
2
3
4
复制代码本文可能是目前最完整的一篇selenium(java版)实践文章,不是之一。
如果你是java开发人员,本文将帮助你快速搭建整套selenium自动化测试框架,你可以帮助公司升级为自动化测试架构;
如果你是测试人员,那你得按照本文多实践一下,遇到不懂的咨询下公司的java开发,同样你也可以完成自动化测试架构升级。
当然啦,如果目前公司已经是自动化测试了,那本文就当是再次梳理下相关知识吧。

前言

可能提到自动化测试selenium,大家都会想到用python语言来编写脚本。但我们选择了java语言,因为我相信大部分公司java程序员比python程序员多得多。而对于很多测试人员,并不能熟练使用编程语言,所以他们需要别人指导。与其使用更简单的python语言,却看不懂语法,得不到别人帮助;那还不如使用java语言,无论是语法还是编程思路,都可以快速获得java开发人员的帮助。

背景

可能很多公司已经有标准的后端单元测试代码,但是自动化测试需要测试整个系统,前端是直接展示给用户的,所以,前端尤为重要,本文就是基于h5的web前端自动化测试。当然啦,这里推荐对项目进行前后端分离,如果项目没有前后端分离可参考某小公司RESTful、共用接口、前后端分离、接口约定的实践

目前互联网上关于selenium完整的文章很少,也很难买到一个专门讲selenium的书籍,这让很多测试人员无从下手,而本文会弥补这一问题,尽可能详细完整介绍selenium的实践,提供一个简易版的完整项目代码在github上(因为公司项目代码没有脱敏,不能直接放到github上)。

相关知识

  1. html标签
  2. css样式
  3. js基础
  4. java基础
  5. bat脚本基础

首先html由标签<x></x>组成,详细本文会在真实项目中一一介绍。

正式实践

安装火狐浏览器

因为selenium在火狐浏览器里,可以自动化录制脚本,我们通过脚本录制可以生成出不同的语言脚本,可以省去我们90%的编写脚本工作量。
可以安装最新版的火狐浏览器,然后安装Katalon Recorder (Selenium IDE for Firefox)
使用火狐浏览器打开https://addons.mozilla.org/zh-CN/firefox/addon/katalon-automation-record/?src=search

录制脚本

以百度搜索掘金为例

  1. 地址栏打开百度
  2. 右上角,打开Katalon扩展
  3. 点击Katalon的New
  4. 点击 Record
  5. 网页中输入 掘金网
  6. 打开第一个掘金官网
  7. 在掘金官网搜索我以前写的一篇文章 我是如何重构整个研发项目,促进自动化运维DevOps的落地?
  8. 点击第一条 我是如何重构整个研发项目,促进自动化运维DevOps的落地?
  9. 点击Katalon的stop

每执行一个操作右下角都会提示

录制后的效果图

运行、分析脚本

录制后,我们点击一下play,可以看到火狐浏览器自动化的完成了我们刚刚的操作(关闭弹窗阻止,或者将掘金和百度加入不阻止弹窗列表)

点击Export

可以看到有各种语言 C#、Java、katalon、python2等。
我们先看看python2的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
复制代码# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re

class Test(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "https://www.katalon.com/"
self.verificationErrors = []
self.accept_next_alert = True

def test_(self):
driver = self.driver
driver.get("https://www.baidu.com/index.php?tn=monline_3_dg")
driver.find_element_by_id("kw").click()
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(u"掘金网")
driver.find_element_by_xpath("//div[@id='container']/div[2]/div").click()
driver.find_element_by_link_text(u"掘金- juejin.im - 一个帮助开发者成长的社区").click()
# ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
driver.find_element_by_xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").click()
driver.find_element_by_xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").click()
driver.find_element_by_xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").clear()
driver.find_element_by_xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").send_keys(u"我是如何重构整个研发项目,促进自动化运维DevOps的落地?")
driver.find_element_by_xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").send_keys(Keys.ENTER)
driver.find_element_by_link_text(u"我是如何重构整个研发项目,促进自动化运维DevOps的落地?").click()

def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True

def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True

def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True

def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)

if __name__ == "__main__":
unittest.main()

我们再看看java junit脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
复制代码package com.example.tests;

import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

public class Test {
private WebDriver driver;
private String baseUrl;
private boolean acceptNextAlert = true;
private StringBuffer verificationErrors = new StringBuffer();

@Before
public void setUp() throws Exception {
driver = new FirefoxDriver();
baseUrl = "https://www.katalon.com/";
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}

@Test
public void test() throws Exception {
driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
driver.findElement(By.id("kw")).click();
driver.findElement(By.id("kw")).clear();
driver.findElement(By.id("kw")).sendKeys("掘金网");
driver.findElement(By.xpath("//div[@id='container']/div[2]/div")).click();
driver.findElement(By.linkText("掘金- juejin.im - 一个帮助开发者成长的社区")).click();
// ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重构整个研发项目,促进自动化运维DevOps的落地?");
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
driver.findElement(By.linkText("我是如何重构整个研发项目,促进自动化运维DevOps的落地?")).click();
}

@After
public void tearDown() throws Exception {
driver.quit();
String verificationErrorString = verificationErrors.toString();
if (!"".equals(verificationErrorString)) {
fail(verificationErrorString);
}
}

private boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}

private boolean isAlertPresent() {
try {
driver.switchTo().alert();
return true;
} catch (NoAlertPresentException e) {
return false;
}
}

private String closeAlertAndGetItsText() {
try {
Alert alert = driver.switchTo().alert();
String alertText = alert.getText();
if (acceptNextAlert) {
alert.accept();
} else {
alert.dismiss();
}
return alertText;
} finally {
acceptNextAlert = true;
}
}
}

python代码量明细比java要少一点,但是本文讲java语言实践。

我们主要关注 java版 @Test注解的那个test方法

1
2
3
4
5
6
7
8
9
10
11
12
13
复制代码    driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
driver.findElement(By.id("kw")).click();
driver.findElement(By.id("kw")).clear();
driver.findElement(By.id("kw")).sendKeys("掘金网");
driver.findElement(By.xpath("//div[@id='container']/div[2]/div")).click();
driver.findElement(By.linkText("掘金- juejin.im - 一个帮助开发者成长的社区")).click();
// ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重构整个研发项目,促进自动化运维DevOps的落地?");
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
driver.findElement(By.linkText("我是如何重构整个研发项目,促进自动化运维DevOps的落地?")).click();

可能很多人已经能看懂了

driver.get(“https://www.baidu.com/index.php?tn=monline\_3\_dg");

打开百度

driver.findElement(By.id(“kw”)).click();

通过id定位到html标签,然后点击click();清空文本框.clear();输入 掘金网3个字 sendKeys(“掘金网”);

这里我们看一下百度的搜索框代码

1
复制代码<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">

driver.findElement(By.linkText(“掘金- juejin.im - 一个帮助开发者成长的社区”)).click();

单击掘金网
通过linktext定位到标签并点击。

后面通过div=juejin一层一层定位到input,最后点击进入文章。

认识html标签

HTML <input>标签

<input>标签用于搜集用户信息。
根据不同的 type 属性值,输入字段拥有很多种形式。输入字段可以是文本字段、复选框、掩码后的文本控件、单选按钮、按钮等等。

1
2
3
4
5
复制代码<form action="form_action.asp" method="get">
First name: <input type="text" name="fname" />
Last name: <input type="text" name="lname" />
<input type="submit" value="Submit" />
</form>

详情参考 http://www.w3school.com.cn/tags/tag\_input.asp

HTML <a>标签

1
2
复制代码<a> 标签定义超链接,用于从一张页面链接到另一张页面。
<a> 元素最重要的属性是 href 属性,它指示链接的目标。

详情参考http://www.w3school.com.cn/tags/tag\_a.asp

HTML <div>标签

<div>可定义文档中的分区或节(division/section)。
<div>标签可以把文档分割为独立的、不同的部分。它可以用作严格的组织工具,并且不使用任何格式与其关联。
如果用 id 或 class 来标记<div>,那么该标签的作用会变得更加有效。

1
2
3
4
复制代码<div style="color:#00FF00">
<h3>This is a header</h3>
<p>This is a paragraph.</p>
</div>

详情参考http://www.w3school.com.cn/tags/tag\_div.asp

…………

其他标签不一一介绍,可在参考网站上意义看

认识css

这里只讲1个关键的,比如

1
复制代码<div class="css1 css2"> ********</div>

表示这个div同时使用了css1和css2样式,只需要知道如果没办法在selenium上定位的这个div,可使用css名定位。

如果有兴趣,可再看下其他css相关知识。

js基础

这里讲2个关键

1
复制代码<a onclick="test()">test</a>

上述代码,点击a标签会执行js中的test方法,当selenium无法定位到这个a标签,可以直接调用test()方法。

可以写简单的js脚本,弹窗代码:

1
复制代码alert("hello");

下载谷歌浏览器

下载谷歌浏览器,这里可以使用63.0.3239.84版本。
目前来说,谷歌浏览器版本兼容性还是不错的。

下载selenium driver

https://www.seleniumhq.org/download/

可不下,本文github项目中包含

下载selenium webdriver

https://npm.taobao.org/mirrors/chromedriver/
需下载和谷歌浏览器对应的版本2.40
可不下,本文github项目中包含

下载idea开发工具

https://www.jetbrains.com/idea/

这个比较复杂,建议在java开发人员指导下完成。

selenium

这个版本是简易版,但足够

最终效果

我们通过录制selenium脚本,编辑,提交到git库,由jenkins自动化编译出jar包,通过bat命令在任意一台pc端执行(默认开发人员提交代码后自动执行所有模块)。按功能模块,测试项目,生成测试报告。对测试不通过的模块

最大化

1
复制代码driver.manage().window().maximize();

打开页面

1
复制代码driver.get("https://www.baidu.com");

定位元素

多个相同时,返回第一个,没有找到会抛异常NoSuchElementException

1
复制代码WebElement element = driver.findElement(*);

当返回多个时:

1
复制代码List<WebElement> elements = driver.findElements(*);

定位元素方式

1
复制代码<input class="input_class input_class2" type="text" name="user-name" id="user-id" />

通过id定位

1
复制代码WebElement element = driver.findElement(By.id("user-id"));

通过name定位

1
复制代码WebElement element = driver.findElement(By.name("user-name"));

通过className定位

1
复制代码WebElement element = driver.findElement(By.className("input_class.input_class2"));

注意多个class用小数点隔开,也可以使用cssSelector定位

1
复制代码WebElement element = driver.findElement(By.cssSelector("input"));

通过linkText定位,如:

1
复制代码WebElement element = driver.findElement(By.linkText("我是如何重构整个研发项目,促进自动化运维DevOps的落地?"));

意思就是链接内容定位

通过partialLinkText定位,模糊内容定位,和上相似

1
复制代码WebElement element = driver.findElement(By.linkText("我是如何重构整个研发项目?"));

通过tagName定位

1
复制代码WebElement element = driver.findElement(By.tagName("form"));

通过xpath定位

1
复制代码WebElement element = driver.findElement(By.xpath("//input[@id='passwd-id']"));

这个最为复杂,最简单的版本是

1
复制代码//标签类型[@属性名=属性值]

但也可以定位第几个

1
复制代码//input[4]

其中[]中还可以增加逻辑and or表达式

1
2
复制代码WebElement element = driver.findElement(By.xpath("//input[@type='text' and @name='user-name']"));
WebElement element = driver.findElement(By.xpath("//input[@type='text' or @name='user-name']"));

[]中也可以增加start-with、ends-with、contains,比如

1
2
3
复制代码WebElement element = driver.findElement(By.xpath("//input[start-with(@id,'user-')]"));
WebElement element = driver.findElement(By.xpath("//input[ends-with(@id,'user-')]"));
WebElement element = driver.findElement(By.xpath("//input[contains(@id,'user-')]"));

还可以 任意属性名

1
复制代码WebElement element = driver.findElement(By.xpath("//input[@*='user-name']"));

更多xpath使用方法见
http://www.w3school.com.cn/xpath/index.asp

单击某个元素

1
复制代码.click()

清空input

1
复制代码.clear();

input中输入内容

1
复制代码.sendKeys("掘金网");

如果是上传附件,可直接sendKeys路径

1
复制代码.sendKeys("c:\shao.png");

得到input内容

1
复制代码.getText();

下拉框

1
2
3
复制代码    Select select = new Select(driver.findElement(By.id("frequency")));
select.selectByValue("1");
driver.findElement(By.id("validDays")).click();
1
2
3
4
5
6
复制代码    select.selectByValue("a"); 
select.deselectAll();
select.deselectByValue("a");
select.deselectByVisibleText("");
select.getAllSelectedOptions();
select.getFirstSelectedOption();

单选框

1
2
3
4
复制代码WebElement radio=driver.findElement(By.id("radio"));
radio.click();&emsp;&emsp;&emsp;&emsp; //选择某个选项
radio.clear();&emsp;&emsp;&emsp;&emsp; //清空选项
radio.isSelected();&emsp;&emsp;//判断某个单选项是否被选中

复选框

1
2
3
复制代码WebElement checkbox = driver.findElement(By.id("checkbox"));
checkbox.clear(); //清空选项
checkbox.isSelected(); //是否选中

判断是否可点击

1
复制代码isEnabled()

alert框操作

1
2
3
复制代码Alert alert = driver.switchTo().alert();
alert.accept();&emsp;&emsp;//确定
alert.dismiss();&emsp; //取消

iframe切换(重点

可能很多老的项目都有iframe,录制脚本的时候正常录制,可执行的时候,却无法执行,这个时候,需要切换iframe

1
2
复制代码driver.switchTo().defaultContent();&emsp;//回到默认的页面
driver.switchTo().frame("leftFrame"); //切换到某个iframe

切换iframe,结束后,记得切换回默认页面。

1
2
3
4
5
6
7
8
9
复制代码        driver.findElement(By.linkText("导入模板")).click();
WebElement iframe = driver.findElement(By.id("layui-layer-iframe1"));
driver.switchTo().frame(iframe);
Thread.sleep(2000);
driver.findElement(By.linkText("引用")).click();
driver.findElement(By.xpath("//button[@type='submit']")).click();
driver.findElement(By.xpath("(//button[@type='button'])[3]")).click();
Thread.sleep(1000);
driver.findElement(By.linkText("学生")).click();

以上摘自项目代码,仅供参考

执行 js

1
2
复制代码    JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("viewDetail('1f50555e409a4597a027ff415ce6c9b4','09','2018')");

执行内部viewDetail方法

延时操作(重要

很多时候我们需要延时,这时使用

1
复制代码Thread.sleep(1000);//延时1000毫秒

许多错误是因为需要等待时间,尝试增加一个延时,也许这个问题就过去了。

项目代码

假设,我们产品有多个环境,我们定义一个environments数组,(当-1时,提示用户输入),有多个模块(当-1时,提示用户输入),最终代码如下,执行后,错误报告会通过邮件发送到指定邮箱或者其他地方。

运行效果图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
复制代码import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import webfunction.*;

import java.util.Scanner;

public class Main {
private static WebDriver driver;
private static String baseUrl;
private boolean acceptNextAlert = true;
/**
* 各个环境
* */
private static String[] environments = {"环境1", "环境2", "环境3", "环境4", "环境5", "环境6"};
/**
* 错误日志
* */
private static StringBuffer verificationErrors = new StringBuffer();
/**
* 是否处于debug模式
*/
private static boolean debug = false;
/**
* -1为手动模式,否则为指定数字
* */
private static String environment = "-1";
/**
* -1为手动模式,否则为指定数字
* */
private static String methods = "-1";

public static void main(String[] args) throws Exception {
//引用火狐浏览器驱动
System.setProperty("webdriver.chrome.driver", "C:\\selenium\\chromedriver.exe");

//定义用户名密码
String uname, upw;
Scanner sc = new Scanner(System.in);
System.out.println("请选择环境");
for (int i = 0; i < environments.length; i++) {
System.out.println(i + ":" + environments[i]);
}
if ("-1".equals(environment)) {
environment = sc.next();
}

System.out.println("请输入需要测试的功能,英文逗号隔开");
if ("-1".equals(methods)) {
methods = sc.next();
}
driver = new ChromeDriver();

System.out.println("您选择的是" + environments[Integer.valueOf(environment)]);
switch (environment) {
case "0":
baseUrl = "http://*.*.*.*/";
uname = "admin";
upw = "admin";
testManage(baseUrl, uname, upw, methods, driver);
break;
case "1":
baseUrl = "http://*.*.*.*/";
uname = "admin";
upw = "admin";
testManage(baseUrl, uname, upw, methods, driver);
break;
case "2":
//等等等……
break;
}

}

private static void testManage(String url, String uname, String upw, String methods, WebDriver driver) throws InterruptedException {
//先登录管理端
WebLogin.webLogin(driver, url, uname, upw);
//然后测试所有模块
String[] strArray = null;
strArray = methods.split(",");
for (int i = 0; i < strArray.length; i++) {
switch (strArray[i]) {
case "0":
try {
// 系统基础管理 - 用户管理 - 新增用户
WebSystemManage.addnewUser(driver, url);
} catch (Exception e) {
verificationErrors.append("系统基础管理 - 用户管理 - 新增用户 出错");
log(e);
}
break;
case "1":
try {
// 系统基础管理 - 用户管理 - 编辑用户
WebSystemManage.editUser(driver, url);
} catch (Exception e) {
System.out.println("系统基础管理 - 用户管理 - 编辑用户 出错");
log(e);
}
break;
default:
break;
}
}
report(verificationErrors);
}

private static void report(StringBuffer verificationErrors) {
//发送邮件
}

/**
* 根据debug变量是否输出日志
* @param e
*/
private static void log(Exception e) {
if (debug) {
e.printStackTrace();
}
}


private static boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}

private static boolean isAlertPresent() {
try {
driver.switchTo().alert();
return true;
} catch (NoAlertPresentException e) {
return false;
}
}

private static String closeAlertAndGetItsText() {
try {
Alert alert = driver.switchTo().alert();
String alertText = alert.getText();
if (acceptNextAlert) {
alert.accept();
} else {
alert.dismiss();
}
return alertText;
} finally {
acceptNextAlert = true;
}
}
}

代码那么多其实我们只关注 public static void main(String[] args) throws Exception {}内的内容,比如,我们想运行我们最初录制的掘金脚本,只需将那端我要求特别关注的代码放到里面即可,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
复制代码import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;

public class Main {
private static WebDriver driver;

public static void main(String[] args) throws Exception {
//引用火狐浏览器驱动
System.setProperty("webdriver.chrome.driver", "C:\\selenium\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
//以下为Katalon Recorder录制后的脚本
driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
Thread.sleep(2000);
driver.findElement(By.id("kw")).click();
driver.findElement(By.id("kw")).clear();
driver.findElement(By.id("kw")).sendKeys("掘金网");
Thread.sleep(100);
driver.findElement(By.id("su")).click();
Thread.sleep(1000);
driver.findElement(By.xpath("//div[@id='container']/div[2]/div")).click();
driver.findElement(By.linkText("掘金- juejin.im - 一个帮助开发者成长的社区")).click();
Thread.sleep(3000);
// ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重构整个研发项目,促进自动化运维DevOps的落地?");
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
Thread.sleep(2000);
driver.findElement(By.linkText("我是如何重构整个研发项目,促进自动化运维DevOps的落地?")).click();
}
}

上述代码中注释内是Katalon Recorder导出的脚本,但是我们增加了一些延时操作,selenium延时有很3种:普通sleep、显示等待方式、隐式等待方式。这里先简单粗暴一下,用Thread.sleep(*);延时,比如打开百度延时2秒、输入“掘金网”延时100毫秒、搜索后延时3秒…………

很遗憾,我们代码报错:

大概意思说超时没有找到那个搜索框,由于各种各样的原因,会导致我们在火狐浏览器中录制的脚本在java代码中的谷歌浏览器里无法兼容,这个时候我们需要去分析一下具体逻辑。
这里是由于新窗口需要切换window,可使用下述代码切换(替换代码中// ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]这行即可)。

1
2
3
4
5
6
7
8
复制代码        Set<String> windowHandles = driver.getWindowHandles();
String windowHandle = driver.getWindowHandle();
for (String handle : windowHandles) {
if (!handle.equals(driver.getWindowHandle())) {
driver.switchTo().window(handle);
break;
}
}

导出的脚本By.xpath(“//div[@id=’juejin’]/div[2]/div/header/div/nav/ul/li[2]/form/input”)这一句很复杂,我们试着简化它。

1
复制代码<input data-v-5ce25e66="" maxlength="32" placeholder="搜索掘金" class="search-input">

首先搜索下search-input样式,看该页面是否只有一个search-input样式。

果然search-input样式只有一个标签。
于是我们将

1
2
3
复制代码By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")
//改为
By.className("search-input")

最终代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
复制代码import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;

import java.util.Set;

public class Main {
private static WebDriver driver;

public static void main(String[] args) throws Exception {
//引用火狐浏览器驱动
System.setProperty("webdriver.chrome.driver", "C:\\selenium\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
Thread.sleep(2000);
driver.findElement(By.id("kw")).click();
driver.findElement(By.id("kw")).clear();
driver.findElement(By.id("kw")).sendKeys("掘金网");
Thread.sleep(100);
driver.findElement(By.id("su")).click();
Thread.sleep(1000);
driver.findElement(By.xpath("//div[@id='container']/div[2]/div")).click();
driver.findElement(By.linkText("掘金- juejin.im - 一个帮助开发者成长的社区")).click();
Thread.sleep(7000);
Set<String> windowHandles = driver.getWindowHandles();
String windowHandle = driver.getWindowHandle();
for (String handle : windowHandles) {
if (!handle.equals(driver.getWindowHandle())) {
driver.switchTo().window(handle);
break;
}
}
// ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重构整个研发项目,促进自动化运维DevOps的落地?");
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
Thread.sleep(2000);
driver.findElement(By.linkText("我是如何重构整个研发项目,促进自动化运维DevOps的落地?")).click();
}
}

编译打包

得到selenium.jar包,可复制到C:\selenium下,和chromedriver.exe同级。

输入cmd命令

1
2
3
复制代码C:\Users\Administrator>cd C:\selenium

C:\selenium>java -jar selenium2.jar

即可自动化运行,非windows系统下载2.40其他版本https://npm.taobao.org/mirrors/chromedriver/2.40/

github项目运行

https://github.com/qq273681448/selenium

为了防止有读者没有改maven库镜像,所以把lib包都放在项目中了。直接使用idea打开,可能有些配置需要改,可参考

写在最后

至此,一个基础版的selenium框架就搭好了,后续,可以连接数据库,从库中随机取出帐号,进行项目测试。也可以配合bat脚本,实现自动化测试以及报告生成。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%