断言及数据驱动测试

断言及数据驱动测试*

实验目的:了解XPath表达式的含义,掌握XPath绝对路径和相对路径的表达方法,能够熟练使用XPath表达式进行元素选择;了解Selenium应用execute_script()函数执行JS的原理,能够在自动化测试过程中完成JS常用操作的执行。

实验要求:在pycharm 环境下完成实验目的中所述各项任务

实验条件:win7/10、pycharm、selenium4.4.0

实验内容及步骤:

每个自动化测试过程都要检查测试结果与预期是否一致,以判断测试用例是否通过。

如果自动化脚本缺少断言,就无法准确获得脚本的运行过程中是否存在非预期的情况,整个测试就不完整。前面的学习中,其实我们使用过if进行断言判断,也应用过try抛出异常进行断言判断,现在来学习通过Assert断言进行判断。

一、 Assert断言的使用:

应用Assert断言时,如果测试失败,将终止该测试。

  1. 页面属性断言:

这是最常用的断言方式,可以用来断言页面是否正常打开,是否在指定的窗口及页面上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 打开百度网站
wd.get('https://www.baidu.com')
wd.maximize_window()
# 点击菜单中'新闻'超链接
wd.find_element(By.LINK_TEXT, '新闻').click()
# 切换到最后一个窗口
wd.switch_to.window(wd.window_handles[-1])

# 断言标题包含'百度新闻'
assert '百度新闻' in wd.title
# 断言为指定url
assert 'https://news.baidu.com/' == wd.current_url
# 断言页面源码不包含not found(一般Nginx找不到页面时返回404页面, 显示Not Found)
assert 'not found' not in wd.page_source

wd.quit()
  1. 图片及链接断言:

图片是否显示以及链接是否能正常打开,我们可以通过driver.get(‘图片或链接地址’),看是否返回404页面来判断图片是否能正常打开。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 打开百度网站
wd.get('https://www.baidu.com')
wd.maximize_window()

baidu_logo_url = wd.find_element(By.ID, 's_lg_img').get_attribute('src')
print('百度Logo图片链接',baidu_logo_url)
# 尝试打开图片
wd.get(baidu_logo_url)
# 假设不存在报错页面包含Not Found字样
assert 'Not Found' not in wd.page_source
wd.back()
hao123_link_url = wd.find_element(By.LINK_TEXT, 'hao123').get_attribute('href')
print('hao123链接', hao123_link_url)
# 尝试打开页面
wd.get(hao123_link_url)
assert 'Not Found' not in wd.page_source
wd.back()
wd.quit()

另一个问题:当我们成功的调试并运行了一个测试用例脚本时,就更想看看使用多组数据运行同样的测试时结果怎样。

这就需要我们将一个测试转化为数据驱动的测试,转化的过程就是将测试数据从测试代码里分离出来,并为要进行测试的多组数据创建一个保存在测试代码外部的数据表文件。执行测试时,依次读取表文件中数据,代替测试脚本中相应的常量值(此为参数化过程),实现不同数据运行同一份代码的操作。

可见,数据驱动测试能够避免编写重复代码,方便验证多组数据测试场景,它很好地体现了自动化测试的优势,使测试运行效率更高。

由于Python有直接操作CSV文件的类库,所以我们以读取CSV文件为例介绍selenium的数据驱动自动化测试。

CSV( Comma Separated Values )逗号分隔值文件:以纯文本形式存储表格数据,由任意数目的记录组成,每条记录由字段组成,字段间的分隔符最常见的是逗号或制表符。看一个实际集图用的CSV 文件中的部分内容,这个文件的格式中逗号隔开的是文件名,文件大小 (以字节为单位),CRC 校验值。

Python要操作CSV文件,需要先打开文件,再执行读取或写入过程。此过程中会用到codecs,这是Python标准的模块编码和解码器,通过codecs提供的open()方法,在打开文件时可以指定编码类型,如utf_8_sig可以解决中文乱码问题。,这要导入codecs库及。CSV库,然后才能使用它。CSV库中有2个最常用的对象:csv.reader:以列表的形式返回读取的数据;csv.writer:以列表的形式写入数据。下面我们来看具体示例。

1
2
3
sj_mino1001.jpg, 715282, 4FB55FE8
sj_mino1002.jpg, 471289, 93203C5C
sj_mino1003.jpg, 451929, C4E80467

二、 Python中获取CSV文件数据的方法:

  1. 以只读方式读取CSV文件:

假设现在要读取的csv文件内容如下:

1
2
3
用户名,密码
byhy,86666666
bbyy,88888888

以只读方式打开CSV文件,得到列表形式的返回数据,然后输出。

1
2
3
4
5
6
7
8
9
# codecs 是 Python 标准的模块编码和解码器
# 通过 codecs 提供的open()方法, 在打开文件时可以指定编码类型,如utf_8_sig可以解决中文乱码问题
import codecs
# 引入CSV包
# 以只读的方式打开CSV文件并读取CSV文件
data = csv.reader(codecs.open('D:\\file\\login,csv', 'r', 'utf_8_sig'))
for line in data:
# line[0]即读取line中的第一列元素
print(line[0], line[1])

执行结果:

1
2
3
用户名 密码
byhy 86666666
bbyy 88888888
  1. 以自动关闭文件的方式打开CSV文件进行写入:(一维列表)

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import codecs
# 引入CSV包
import csv
# 新建列表存储要写入的信息
list_1 = ['name', 'height']
list_2 = ['Mike', '180']
list_3 = ['Bob', '175']
list_4 = ['Andy', ' 170']

# 以自动关闭文件的方式打开CSV文件进行写入
with codecs.open('D:\\file\\health.csv', 'w', 'utf_8') as f:
data_writer = csv.writer(f)
data_writer.writerow(list_1)
data_writer.writerow(list_2)
data_writer.writerow([list_3, list_4])
data = csv.reader(codecs.open('D:\\file\\health.csv', 'r', 'utf_8'))
for line in data:
# line[0]即读取line中的第一列元素
print(line[0], line[1])

执行结果:

1
2
3
4
name height
Mike 180
Bob 175
Andy 170

得到一个新文件:

wps9

  1. 以自动关闭文件的方式打开CSV文件进行写入:(二维列表)

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import codecs
# 引入CSV包
import csv

# 新建列表存储要写入的信息
# 创建列表, 保存header内容
header_list = ["设备编号", "温度", "湿度", "转速"]
# 创建列表, 保存数据
data_list = [
[0, 31, 20, 1000],
[1, 30, 22, 998],
[2, 32, 33, 1005]
]
# 以自动关闭文件的方式打开CSV文件进行写入
with codecs.open('D:\\file\\equipment.csv', 'w', 'utf_8') as f:
data_writer = csv.writer(f)
# 一次只能写入一行
data_writer.writerow(header_list)
# 一次写入多行
data_writer.writerows(data_list)
data = csv.reader(codecs.open('D:\\file\\equipment.csv', 'r', 'utf_8'))
for line in data:
# line[0] 即读取line中的第一列元素
print(line[0], line[1], line[2], line[3])

执行结果:

1
2
3
4
设备编号 温度 湿度 转速
0 31 20 1000
1 30 22 998
2 32 33 1005

得到一个新文件:

wps12

4. 将CSV文件中的数据应用到测试脚本中:

wps13

例如,要读取如下的CSV文件,完成在百度首页进行的多数据搜索。

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
wd.get('https://www.baidu.com')
# 读取CSV文件并以只读的方式打开CSV文件
keys = csv.reader(codecs.open('D:\\file\\search.csv', 'r', 'utf_8_sig'))
for text in keys:
# text即读取keys中的第一列元素
print(text)
wd.find_element(By.XPATH, '//input[@id="kw"]').clear()
wd.find_element(By.XPATH, '//input[@id="kw"]').send_keys(text)
wd.find_element(By.ID, 'su').click()
sleep(2)
print(wd.title)

wd.quit()

执行结果:经过四次搜索,会得到四个查询结果,输出内容中显示了要搜索的内容及查询后网页的标题。

wps15

练习1:在医疗销售管理系统 http://127.0.0.1:8047/mgr/sign.html 中对异常登录进行测试。要求:分别设计5个测试用例,包括:用户名为空、密码为空、用户名错误、密码错误、用户名和密码都错。在excel文件中编写自己设计的测试用例(注意:测试用例要完整,既有测试数据,也要有预期结果),将其另存为csv格式的文档。测试程序读取该文件,根据文件中的预期结果进行断言判断。

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
import codecs, csv
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from time import sleep
from os.path import dirname, join as path_join
import traceback


def login():
browser = webdriver.Chrome()
return browser


def open_and_close(fun):
def func(*args, **kwargs):
fun_data = ""
try:
browser = login()
except Exception as e:
print("创建句柄出错了", e)
else:
try:
browser.implicitly_wait(3)
fun_data = fun(browser, *args, **kwargs)
except Exception as e:
print("出错了", e)
traceback.print_exc()
browser.close()
return fun_data

return func


@open_and_close
def fun1(browser):
browser.get('http://127.0.0.1:8047/mgr/sign.html/')
reader = csv.reader(codecs.open(path_join(dirname(__file__), "login_test.csv"), "r", "gbk"))
next(reader)
for line in reader:
account = line[0]
password = line[1]
browser.find_element(By.CSS_SELECTOR, "[placeholder='用户名']").clear()
browser.find_element(By.CSS_SELECTOR, "[placeholder='密码']").clear()
browser.find_element(By.CSS_SELECTOR, "[placeholder='用户名']").send_keys(account)
browser.find_element(By.CSS_SELECTOR, "[placeholder='密码']").send_keys(password)
browser.find_element(By.CSS_SELECTOR, ".row div button").click()
sleep(0.5)
try:
assert not EC.alert_is_present()(browser), "登录错误"
except Exception as e:
EC.alert_is_present()(browser).accept()
if not account:
print(line[2])
elif not password:
print(line[2])
elif account != "byhy" and password != "88888888":
print(line[2])
elif account != "byhy":
print(line[2])
elif password != "88888888":
print(line[2])


if __name__ == "__main__":
fun1()

练习2:在医疗销售管理系统中先运行学号+UI_8测试用例,保证系统中有数据。再完成以下测试过程的编写:正常登录http://127.0.0.1:8047/mgr/sign.html 后,点击药品按钮,依次获取已有药品信息,将药品名称中的“头孢”替换为“阿奇霉素”;编号改为“H20010556 ”(另外两个末位为5和4),描述信息改为“阿奇霉素注射液,每支2ml,10支装” (另外两个为20支和30支装)。改好的信息保存至medicine.csv文件中,再从文件中读取信息完成新药品的添加操作。

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
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from time import sleep
from os.path import isfile, dirname, join as path_join
import traceback
import codecs, csv


def login():
browser = webdriver.Chrome()
return browser


def open_and_close(fun):
def func(*args, **kwargs):
fun_data = ""
try:
browser = login()
except Exception as e:
print("创建句柄出错了", e)
else:
try:
browser.implicitly_wait(1)
fun_data = fun(browser, *args, **kwargs)
except Exception as e:
print("出错了", e)
traceback.print_exc()
browser.close()
return fun_data

return func


@open_and_close
def fun1(browser):
browser.get('http://127.0.0.1:8047/mgr/sign.html/')
account = 'byhy'
password = '88888888'
drug_list = [
['头孢盒装1', 'YP-20023524', '头孢他啶注射液,每支15ml,10支装'],
['头孢盒装2', 'YP-20023525', '头孢他啶注射液,每支15ml,20支装'],
['头孢盒装3', 'YP-20023526', '头孢他啶注射液,每支15ml,30支装']
]
client_list = [
['南京鼓楼区中医院1', '2583426507', '江苏省-南京市-鼓楼区-中山北路-253'],
['南京鼓楼区中医院2', '2583426508', '江苏省-南京市-鼓楼区-中山北路-254'],
['南京鼓楼区中医院3', '2583426509', '江苏省-南京市-鼓楼区-中山北路-255']
]
num = 0
li_list = [["订单", 2], ["客户", 0], ["药品", 1]]
browser.find_element(By.CSS_SELECTOR, "[placeholder='用户名']").send_keys(account)
browser.find_element(By.CSS_SELECTOR, "[placeholder='密码']").send_keys(password)
browser.find_element(By.CSS_SELECTOR, ".row div button").click()
sleep(1)
assert browser.title == "白月销售管理系统", "没有登录成功"
for i in li_list:
browser.find_element(By.XPATH, f"/html/body/div/aside/section/ul/li[{2 + i[1]}]/a").click()
while browser.find_elements(By.XPATH, "/html/body/div/div/section[2]/div[3]//label[last()]"):
# 每次删除前判断
assert browser.find_element(By.XPATH, "/html/body/div/div/section[2]/div[1]/button").text[-2:] == i[
0], "菜单项出错"
# print(i,browser.find_elements(By.XPATH,"/html/body/div/div/section[2]/div[3]//label[last()]"))
browser.find_elements(By.XPATH, "/html/body/div/div/section[2]/div[3]//label[last()]")[0].click()
assert EC.alert_is_present()(browser), "不存在删除弹出框"
if EC.alert_is_present()(browser):
EC.alert_is_present()(browser).accept()
sleep(0.3)
if EC.alert_is_present()(browser):
# 防止出现服务器500错误的提示
EC.alert_is_present()(browser).accept()
break

# return
for temp in [client_list, drug_list]:
browser.find_element(By.XPATH, f"/html/body/div/aside/section/ul/li[{2 + num}]/a").click()
browser.find_element(By.XPATH, "/html/body/div/div/section[2]/div[1]/button").click()
input_div = browser.find_element(By.XPATH, '/html/body/div/div/section[2]/div[1]')
input_list = input_div.find_elements(By.XPATH, "//input")
for i in temp:
input_list[0].send_keys(i[0])
input_list[1].send_keys(i[1])
input_div.find_element(By.XPATH, '//textarea').send_keys(i[2])
input_div.find_elements(By.XPATH, "//button")[1].click()
sleep(0.5)
num += 1
sleep(1)
# 判断是否正确添加客户 药品新对象
assert browser.find_elements(By.XPATH, "/html/body/div/div/section[2]/div[3]"), "没有正确添加客户 药品新对象"
browser.find_element(By.XPATH, f"/html/body/div/aside/section/ul/li[{2 + num}]/a").click()
browser.find_element(By.XPATH, "/html/body/div/div/section[2]/div[1]/button").click()
input_div = browser.find_element(By.XPATH, '/html/body/div/div/section[2]/div[1]')
input_list = input_div.find_elements(By.XPATH, "//input")
input_list[0].send_keys('南京鼓楼中院头孢')

temp_select = Select(browser.find_element(By.XPATH, "/html/body/div[1]/div/section[2]/div[1]/div[1]/div[2]/select"))
temp_select.select_by_visible_text("南京鼓楼区中医院2")

temp_select = Select(browser.find_element(By.XPATH, "/html/body/div[1]/div/section[2]/div[1]/div[1]/div[3]/select"))
temp_select.select_by_visible_text("头孢盒装1")
temp_select.select_by_visible_text("头孢盒装2")

input_list = browser.find_elements(By.XPATH, "/html/body/div[1]/div/section[2]/div[1]/div[1]/div[3]//input")
input_list[0].send_keys(100)
input_list[1].send_keys(100)
input_div.find_elements(By.XPATH, "//button")[1].click()

# 判断是否正确添加订单新对象
assert browser.find_elements(By.XPATH, "/html/body/div/div/section[2]/div[3]"), "没有正确添加订单新对象"

# 获取信息保存修改信息到csv
browser.find_element(By.XPATH, "/html/body/div/aside/section/ul/li[3]/a").click()
num = 0
with codecs.open(path_join(dirname(__file__), "medicine.csv"), "w", "utf_8") as f:
data_writer = csv.writer(f)
while browser.find_elements(By.XPATH, f"/html/body/div/div/section[2]/div[{3 + num}]"):
div = browser.find_element(By.XPATH, f"/html/body/div/div/section[2]/div[{3 + num}]")
drug = div.find_element(By.CSS_SELECTOR, "div:nth-child(1) > span:nth-child(2)").text
drug_code = f"H2001055{6 - num}"
drug_text = div.find_element(By.CSS_SELECTOR, "div:nth-child(3) > span:nth-child(2)").text
drug = "阿奇霉素" + drug[2:]
drug_text = "阿奇霉素" + drug_text[4:10]+"2"+drug_text[12:]
print(drug_text)
num += 1
data_writer.writerow([drug, drug_code, drug_text])

# 读取信息完成药品添加操作
for line in csv.reader(codecs.open(path_join(dirname(__file__), "medicine.csv"), "r", "utf_8_sig")):
browser.find_element(By.XPATH, "/html/body/div/div/section[2]/div[1]/button").click()
input_div = browser.find_element(By.XPATH, '/html/body/div/div/section[2]/div[1]')
input_list = input_div.find_elements(By.XPATH, "//input")
input_list[0].send_keys(line[0])
input_list[1].send_keys(line[1])
input_div.find_element(By.XPATH, '//textarea').send_keys(line[2])
input_div.find_elements(By.XPATH, "//button")[1].click()


if __name__ == "__main__":
fun1()
print('测试通过')

断言及数据驱动测试
http://example.com/2025/01/07/测试笔记/selenium/selenium10/
作者
Helios
发布于
2025年1月7日
许可协议