Selenium is a suite of tools to automate web browsers across many platforms.
runs in many browsers and operatingsystems
can be controlled by many programming languages and testing frameworks.
Selenium 是用于测试 Web 应用程序用户界面 (UI) 的常用框架。它是一款用于运行端到端功能测试的超强工具。您可以使用多个编程语言编写测试,并且 Selenium 能够在一个或多个浏览器中执行这些测试。
Client Libraries 库主要主要用于编写测试脚本,用来控制selenium Server 的库。
Selenium Server 负责控制浏览器行为,总的来说,Selenium Server 主要包括3 个部分:Launcher、Http Proxy、Core。
Selenium Grid
get(url): 打开web页面
findElement(by, selector): 查找一个页面元素
配合浏览器的开发者工具(推荐 Chrome Developer Tools),有8中方式定位元素:
id:元素标签的 id
css selector:元素标签的 selector
xpath:元素标签的 XPath
link text:元素标签的完整文字
name:元素标签的 name
class name:元素标签的 class name
tag name:元素标签的 tag name
partial link text:元素标签的部分文字
findElements(by, selector):查找一组具有同一属性的页面元素,方式同上。
@BeforeMethod: Method annotated with @BeforeMethod executes before every test method.
@AfterMethod: Method annotated with @AfterMethod executes after every test method.
如果在测试之前有些工作我们只想做一次,用不着每个函数之前都做一次,那就用下面两个来标注:
@BeforeTest: 在第一个 test method 开始执行前,执行。
@AfterTest: 在最后一个 test method 执行后再执行。
接下来我们用具体的代码示例,解释单元测试框架的使用
TestNG 框架图
TestNG 断言
方法 Method 检查条件
assertEquals(a, b [, msg]) a == b,msg可选,用来解释失败的原因
assertNotEquals(a, b [, msg] a != b,msg可选,用来解释失败的原因
assertTrue(x [, msg]) x 是真,msg可选,用来解释失败的原因
assertFalse(x [, msg]) x 是假,msg可选,用来解释失败的原因
assertIsNot(a, b [, msg]) a 不是 b,msg可选,用来解释失败的原因
assertNull(x[, msg]) x 是null,msg可选,用来解释失败的原因
assertNotNull(x[, msg]) x 不是null,msg可选,用来解释失败的原因
TestNG 的引入
这里我们依旧使用 Maven 的方式,引入 TestNG 到项目中。
public void switchToFrame(String selector) {
WebElement we = this.locateElement(selector);
this.baseDriver.switchTo().frame(we);
}
1
2
3
4
找到一个指定的select,并且通过index进行选择
selectByIndex(selector, index)
public void selectByIndex(String selector, int index) {
WebElement we = this.locateElement(selector);
Select s = new Select(we);
s.selectByIndex(index);
}
1
2
3
4
5
以上的代码是封装了locateElement()的几种方法,在具体使用封装过的代码的时候,只需要简单的调用即可。接下来的重点,是介绍 locateElement(selector)的封装方式。
查找元素:findElement(By...)
支持各种的查找:8种方式都需要支持,必须通过 selector 显示出分类
selector中需要包含一个特殊符号
实例化 封装好的类的时候,需要约定好是什么特殊符号
强制性用硬编码 hard code来实例化,例如 , 或者 ? 或者 其他非常用字符 =>
或者,构造方法中,传递 this.byChar
要把查找到元素的返回给调用的地方:必须要有返回值,类型是 WebElement
private WebElement locateElement(String selector) {
WebElement we;
// 如果定位符中 有 分隔符,那么就从分隔符处分成两段
// 第一段是By
// 第二段是真正的定位符
// 如果没有分隔符,就默认用 id 定位
if (!selector.contains(this.byChar)) {
// 用 id 定位
we = this.baseDriver.findElement(By.id(selector));
} else {
// 用 分隔符 分成两个部分
String by = selector.split(this.byChar)[0];
String value = selector.split(this.byChar)[1];
we = findElementByChar(by, value);
}
return we;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
接下来的重点,是实现 findElementByChar(by, value)
private WebElement findElementByChar(String by, String value) {
WebElement we = null;
switch (by.toLowerCase()) {
case "id":
case "i":
we = this.baseDriver.findElement(By.id(value));
break;
case "css_selector":
case "css":
case "cssselector":
case "s":
we = this.baseDriver.findElement(By.cssSelector(value));
break;
case "xpath":
case "x":
we = this.baseDriver.findElement(By.xpath(value));
break;
case "link_text":
case "link":
case "text":
case "linktext":
case "l":
we = this.baseDriver.findElement(By.linkText(value));
break;
//TODO: other by type
}
return we;
}
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
使用上面的封装类,就需要指定特定的 selector
类型 示例(分隔符以逗号,为例) 描述
id “account” 或者 “i,account” 或者 “id,account” 分隔符左右两侧不可以空格
xpath “x,//*[@id=”s-menu-dashboard”]/button/i”
css selector “s,#s-menu-dashboard > button > i”
link text “l,退出”
partial link text “p,退”
name “n,name1”
tag name “t,input”
class name “c,dock-bottom
调用的具体示例
Git 是目前主流的源代码管理工具,本文推荐的两个 IDE 工具: JetBrains IDEA 和 JetBrains Pycharm 都是默认支持 Git 的。只需要按照以下步骤进行配置,便可以通过 IDE 工具对代码进行提交,这样可以防止代码丢失,以及方便的查询代码的修改历史,同时很方便团队的编码。
public class Main {
public static void main(String[] args) {
TestNG test = new TestNG();
List<String> suites = new ArrayList<>();
suites.add("testng.xml");
test.setTestSuites(suites);
test.run();
}
}
1
2
3
4
5
6
7
8
9
@Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd_HHmmss");
String time = formatter.format(date);
添加 test suite
suite = unittest.TestSuite()
suite.addTest(LoginTests("test_login_by_csv"))
suite.addTest(LoginTests("test_login_by_csv2"))
suite.addTest(AdminTests("test_add_member_by_csv"))
1
2
3
4
这里可以配置测试,到外部文件,数据库中等。
持续集成正是针对这一类问题的一种软件开发实践。首先我们看一下,敏捷教父 Martin Fowler 对持续集成的定义:
Martin Fowler:Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly.
具体定义:持续集成式一种软件开发实践。它倡导团队的成员必须经常的集成他们的工作,通常至少每天一次甚至更多次集成。每次集成都需要通过自动化的构建(包括编译代码、构建应用、部署程序以及自动化测试)来验证,从而尽早尽快的发现集成中的错误。大量的团队利用这样的方式来更快的开发内聚的软件。大大减少此过程中的集成问题。