zoukankan      html  css  js  c++  java
  • 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"]的方式获取。

  • 相关阅读:
    Win7 vs2017 WDK 1803 1809 驱动开发 出错 KMDF
    http 请求 post get 长度限制
    IO模式和IO多路复用(阻塞IO、非阻塞IO、同步IO、异步IO等概念)
    select/poll 和 epoll 比较
    centos查看端口被哪个应用端口占用命令
    mysql索引知识简单记录
    Spring钩子方法和钩子接口的使用详解
    mysql使用自增Id为什么存储比较快
    分布式Id教程
    如何配置JVM系统属性及获取方式System.getProperty("pname")
  • 原文地址:https://www.cnblogs.com/pegawayatstudying/p/12200172.html
Copyright © 2011-2022 走看看