Selenium实战——数据驱动应用
Posted pegawayatstudying
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Selenium实战——数据驱动应用相关的知识,希望对你有一定的参考价值。
一、数据驱动
由于大多数文章和资料都把“读取数据文件”看做数据驱动的标志,下面创建一个baidu_data.csv文件:
文件第一列为测试用例名称,第二列为搜索的关键字。接下来创建test_baidu_data.py文件:
1 import csv 2 import codecs 3 import unittest 4 from time import sleep 5 from itertools import islice 6 from selenium import webdriver 7 8 9 class TestBaidu(unittest.TestCase): 10 11 @classmethod 12 def setUpClass(cls): 13 cls.driver = webdriver.Chrome() 14 cls.base_url = "https://www.baidu.com" 15 16 @classmethod 17 def tearDownClass(cls): 18 cls.driver.quit() 19 20 def baidu_search(self, search_key): 21 self.driver.get(self.base_url) 22 self.driver.find_element_by_id("kw").send_keys(search_key) 23 self.driver.find_element_by_id("su").click() 24 sleep(3) 25 26 def test_search(self): 27 with codecs.open(‘baidu_data.csv‘, ‘r‘, ‘utf_8_sig‘) as f: 28 data = csv.reader(f) 29 for line in islice(data, 1, None): 30 search_key = line[1] 31 self.baidu_search(search_key) 32 33 34 if __name__ == ‘__main__‘: 35 unittest.main(verbosity=2)
这样做将所有的测试数据当做一条测试用例并行地执行,如果有一条测试数据有误就会导致这条测试用例执行失败,显然是不合理的。因此做如下修改:
1 import csv 2 import codecs 3 import unittest 4 from time import sleep 5 from itertools import islice 6 from selenium import webdriver 7 8 9 class TestBaidu(unittest.TestCase): 10 11 @classmethod 12 def setUpClass(cls): 13 cls.driver = webdriver.Chrome() 14 cls.base_url = "https://www.baidu.com" 15 cls.test_data = [] 16 with codecs.open(‘baidu_data.csv‘, ‘r‘, ‘utf_8_sig‘) as f: 17 data = csv.reader(f) 18 for line in islice(data, 1, None): 19 cls.test_data.append(line) 20 21 @classmethod 22 def tearDownClass(cls): 23 cls.driver.quit() 24 25 def baidu_search(self, search_key): 26 self.driver.get(self.base_url) 27 self.driver.find_element_by_id("kw").send_keys(search_key) 28 self.driver.find_element_by_id("su").click() 29 sleep(3) 30 31 def test_search_selenium(self): 32 self.baidu_search(self.test_data[0][1]) 33 34 def test_search_unittest(self): 35 self.baidu_search(self.test_data[1][1]) 36 37 def test_search_parameterized(self): 38 self.baidu_search(self.test_data[2][1]) 39 40 41 if __name__ == ‘__main__‘: 42 unittest.main(verbosity=2)
这一次,用setUpClass()方法读取baidu_data.csv文件,并将文件中的数据存储到test_data数组中,分别创建不同的测试方法使用test_data中的数据,结果如下
从测试结果可看出,存在以下问题:
- 增加了读取的成本。不管什么样的数据文件,在运行自动化测试用例前都需要将文件中的数据读取到程序中,这一步必不可少。
- 不方便维护。在CSV数据文件中,并不能直观体现出每一条数据对应的测试用例。而在测试用例中通过test_data[0][1]方式获取数据也存在很多问题,如果在csv文件中间插入了一条数据,那么测试用例获取到的测试数据很可能是错误的。
二、Parameterized
Parameterized是Python的一个参数化库,同时支持unittest、Nose和pytest单元测试框架。
GitHub地址:https://github.com/wolever/parameterized
Parameterized支持pip安装:pip install parameterized
导入parameterized后修改test_baidu_data.py文件如下:
1 import unittest 2 from time import sleep 3 from selenium import webdriver 4 from parameterized import parameterized 5 6 7 class TestBaidu(unittest.TestCase): 8 9 @classmethod 10 def setUpClass(cls): 11 cls.driver = webdriver.Chrome() 12 cls.base_url = "https://www.baidu.com" 13 14 @classmethod 15 def tearDownClass(cls): 16 cls.driver.quit() 17 18 def baidu_search(self, search_key): 19 self.driver.get(self.base_url) 20 self.driver.find_element_by_id("kw").send_keys(search_key) 21 self.driver.find_element_by_id("su").click() 22 sleep(3) 23 24 # 通过Parameterized实现参数化 25 @parameterized.expand([ 26 ("case1", "selenium"), 27 ("case2", "unittest"), 28 ("case3", "parameterized"), 29 ]) 30 def test_search(self, name, search_key): 31 self.baidu_search(search_key) 32 self.assertEqual(self.driver.title, search_key + "_百度搜索") 33 34 35 if __name__ == ‘__main__‘: 36 unittest.main(verbosity=2)
通过@parameterized.expand()来装饰测试用例test_search()。在@parameterized.expand()中,每个元组都可以被认为是一条测试用例。元组中的数据为该条测试测试用例变化的值。在测试用例中,通过参数来取每个元组中的数据。
在test_search()中,name参数对应元组中第一列数据,即"case1""case2""case3",用来定义测试用例的名称;search_key参数对应元组中第二列数据,即"sselenium""unittest""parameterized",用来定义搜索的关键字。
,
通过测试结果可以看到,因为是根据@parameterized.expand()中元组的个数来统计测试用例数的,所以产生了三条测试用例。test_search为定义的测试用例的名称。参数化会自动加上“0”、“1”、“2”来区分每条测试用例,在元组中定义的“case1”、“case2”、“case3”也会作为每条测试用例名称的后缀出现。
三、DDT
DDT(Data-Driven Tests)是针对unittest单元测试框架设计的扩展库。允许使用不同的测试数据来运行一个测试用例,并将其展示为多个测试用例。
GitHub地址:https://github.com/datadriventests/ddt
DDT支持pip安装:pip install ddt
创建一个test_baidu_ddt.py文件:
1 import unittest 2 from time import sleep 3 from selenium import webdriver 4 from ddt import ddt, data, file_data, unpack 5 6 7 @ddt 8 class TestBaidu(unittest.TestCase): 9 10 @classmethod 11 def setUpClass(cls): 12 cls.driver = webdriver.Chrome() 13 cls.base_url = "https://www.baidu.com" 14 15 def baidu_search(self, search_key): 16 self.driver.get(self.base_url) 17 self.driver.find_element_by_id("kw").send_keys(search_key) 18 self.driver.find_element_by_id("su").click() 19 sleep(3) 20 21 # 参数化使用方式一 22 @data(["case1", "selenium"], ["case2", "unittest"], ["case3", "python"]) 23 @unpack 24 def test_search1(self, case, search_key): 25 print("第一组测试用例:", case) 26 self.baidu_search(search_key) 27 self.assertEqual(self.driver.title, search_key + "_百度搜索") 28 29 # 参数化使用方式二 30 @data(("case1", "selenium"), ("case2", "unittest"), ("case3", "python")) 31 @unpack 32 def test_search2(self, case, search_key): 33 print("第二组测试用例:", case) 34 self.baidu_search(search_key) 35 self.assertEqual(self.driver.title, search_key + "_百度搜索") 36 37 @data({"search_key": "selenium"}, {"search_key": "unittest"}, {"search_key": "python"}) 38 @unpack 39 def test_search3(self, search_key): 40 print("第三组测试用例:", search_key) 41 self.baidu_search(search_key) 42 self.assertEqual(self.driver.title, search_key + "_百度搜索") 43 44 @classmethod 45 def tearDownClass(cls): 46 cls.driver.quit() 47 48 49 if __name__ == ‘__main__‘: 50 unittest.main(verbosity=2)
使用DDT需要注意以下几点:
- 首先,测试类需要通过@ddt进行装饰
- 其次,DDT提供了不同形式的参数化。这里列举了三组参数化,第一组为列表,第二组为元组,第三组为字典。需要注意的是,字典的key与测试方法的参数要保持一致。
同样的,DDT也支持数据文件的参数化。它封装了数据文件的读取,让我们更专注于数据文件中的内容,以及在测试用例中的使用,而不必关心数据文件时如何被读取进来的。
首先,创建ddt_data_file.json文件
1 { 2 "case1": {"search_key": "python"}, 3 "case2": {"search_key": "ddt"}, 4 "case3": {"search_key": "Selenium"} 5 }
在测试用例中使用ddt_data_file.json文件参数化测试用例,在test_baidu_ddt.py文件中增加测试用例数据:
1 # 参数化读取JSON文件 2 @file_data(‘ddt_data_file.json‘) 3 def test_search4(self, search_key): 4 print("第四组测试用例:", search_key) 5 self.baidu_search(search_key) 6 self.assertEqual(self.driver.title, search_key + "_百度搜索")
除此之外,DDT还支持yaml格式的数据文件。创建ddt_data_file.yaml文件:
1 case1: 2 - search_key: "python" 3 case2: 4 - search_key: "ddt" 5 case3: 6 - search_key: "Selenium"
在test_baidu_ddt.py文件中增加测试用例:
1 # 参数化读取yaml文件 2 @file_data(‘ddt_data_file.yaml‘) 3 def test_search5(self, case): 4 search_key = case[0]["search_key"] 5 print("第五组测试用例: ", search_key) 6 self.baidu_search(search_key) 7 self.assertEqual(self.driver.title, search_key + "_百度搜索")
执行结果如下:
这里的取值与上面的JSON文件有所不同,因为每一条用例都被解析为[{‘search_key‘:‘python‘}],所以要想渠道搜索关键字,则需要通过case[0]["search_key"]的方式获取。
以上是关于Selenium实战——数据驱动应用的主要内容,如果未能解决你的问题,请参考以下文章
好书送不停| 周四《Selenium WebDriver 3.0 自动化测试框架实战指南》
selenium(12)-web UI自动化项目实战(PO模式,代码封装)
Express实战 - 应用案例- realworld-API - 路由设计 - mongoose - 数据验证 - 密码加密 - 登录接口 - 身份认证 - token - 增删改查API(代码片段