自动化测试之数据驱动DDT


引言

你是否有过这种感受,在做自动化测试过程中,不论是API 自动化测试还是UI 自动化测试,我们写测试脚本有很大一部分时间都是在准备数据(setUp)、清理数据(tearDown)。因为数据是做自动化测试的至关重要的一个环节。如此看来数据驱动真的十分重要。接下来分享的内容是:Unittest测试框架中常用的数据驱动框架:DDT 。

数据驱动

加油

  • 1、数据驱动是什么?
  • 2、数据驱动的优点?
  • 3、Python 中使用广泛的数据驱动框架有哪些?
    • 1 个类装饰器
    • 2 个方法装饰器
  • Python 安装DDT :
    • (1)、ddt 直接提供数据
    • (2)ddt 使用函数提供数据
    • 关于 ddt 使用文件提供数据:JSON 和 YAML

1、数据驱动是什么?

  数据驱动,指在自动化测试中处理测试数据的方式。

通常测试数据与功能函数分离,存储在功能函数的外部位置。在自动化测试运行时,数据驱动框架会读取数据源中的数据,把数据作为参数传递到功能函数中,并会根据数据的条数多次运行同一个功能函数。

数据驱动的数据源可以是函数外的数据集合、CSV 文件、Excel 表格、TXT 文件,以及数据库等。

2、数据驱动的优点?

(1)、减少重复代码
通过以下实例来看下数据驱动是如何减少重复代码的。

如果不使用数据驱动时,并且同一个功能函数存在多个测试数据,你只能多次调用这个功能函数;另外一旦某一个测试数据有更改/删除,你需要在函数调用里去更改相应的测试数据,非常不方便。

如果使用测试驱动时,你的代码可能会是这样的:

# origin_data指向一个文件,这个文件里存储有你所有的测试数据。
origin_data = './tests/data/testdata.csv'
 
# dataDrivenDecorator是你实现数据驱动的装饰器
 
@dataDrivenDecorator(origin_data)
def test_001(user, pwd, num):
    # 实际函数逻辑
    pass

这种情况下, 你无须进行多次调用,而且当你的测试数据发生改变时, 你仅需要更改数据源文件的数据就可以了。

3、Python 中使用广泛的数据驱动框架有哪些?

DDT(Data-Driven Tests),通常结合Unittest 使用

parameterized,是Pytest 实现数据驱动的常用框架

DDT 包含哪些装饰器

1 个类装饰器

ddt 这个类装饰器必须装饰在TestCase 的子类上,TestCase 是Unittest 框架中的一个基类,它实现了Test Runner 驱动测试运行所需的接口(interface)。

2 个方法装饰器

分别是:data 和 file_data。
  data 装饰器,直接提供测试数据;
  file_data 装饰器则从 JSON 或 YAML 文件加载测试数据。

DDT 的使用步骤如下:
使用@ddt 装饰你的测试类;

使用@data 或者@file_data 装饰你需要数据驱动的测试方法;

如一组测试数据有多个参数,则需unpack,使用@unpack 装饰你的测试方法。

Python 安装DDT :

安装命令:pip install ddt或python -m pip install ddt
DDT 的使用

(1)、ddt 直接提供数据

from ddt import ddt, data, file_data, unpack
from selenium import webdriver
import unittest
import time
 
# ddt一定是装饰在TestCase的子类上
@ddt
class Baidu(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(30)
        self.base_url = "http://www.baidu.com/"
 
    # data表示测试数据是直接提供的。
    # unpack表示,对于每一组数据,如果它的值是list或者tuple,那么就分拆成独立的参数。
 
    @data(['Testing', 'Testing'], ['hello_world.com','Testing'])
    @unpack
    def test_baidu_search(self, search_string, expect_string):
        driver = self.driver
        driver.get(self.base_url + "/")
        driver.find_element_by_id("kw").send_keys(search_string)
        driver.find_element_by_id("su").click()
        time.sleep(2)
        search_results = driver.find_element_by_xpath('//*[@id="1"]/h3/a').get_attribute('innerHTML')
        print(search_results)
        self.assertEqual(expect_string in search_results, True)
 
    def tearDown(self):
        self.driver.quit()
 
if __name__ == "__main__":
    unittest.main(verbosity=2)

在这个例子中,我直接使用了@data 装饰器。在这个装饰器中,我给出了测试的2 组数据,分别是 [‘Testing’, ‘Testing’] 和 [‘hello_world.com’, ‘Testing’];然后我使用 @unpack 装饰器把每一组数据的数据unpack 成一个个的参数传给我的函数 test_baidu_search。

当你运行上面代码,从结果中会发现虽然我们只有一个测试用例test_baidu_search。但在生成的测试报告里,显示“Run 2 tests in XX”,也就是test_baidu_search 运行了 2 次,这就是DDT 在起作用。

(2)ddt 使用函数提供数据

ddt 直接提供数据,除去上述的直接把数据写在@data() 的参数中外,还有一个情况,即数据先从函数获取,然后再写入@data() 的参数中。

from ddt import ddt, data, file_data, unpack
from selenium import webdriver
import unittest
import time
 
def get_test_data():
    # 这里写你获取测试数据的业务逻辑。
 
    # 获取到后,把数据返回即可。
 
    # 注意,如果多组数据,需要返回类似([数据1-参数1, 数据1-参数2],[数据2-参数1, 数据2-参数2])这样的格式,方便ddt.data()解析
 
    # 解析后返回的数据格式如下:
    results = (['Testing', 'Testing'], ['hello_world.com', 'Testing'])
    return results
 
# ddt一定是装饰在TestCase的子类上
 
@ddt
class Baidu(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(30)
        self.base_url = "http://www.baidu.com/"
 
    # data表示data是直接提供的。注意data里的参数我写了函数get_test_data()的返回值,并且以*为前缀,代表返回的是可变参数。
 
    # unpack表示,对于每一组数据,如果它的值是list或者tuple,那么就分拆成独立的参数。
 
    @data(*get_test_data())
    @unpack
    def test_baidu_search(self, search_string, expect_string):
        driver = self.driver
        driver.get(self.base_url + "/")
        driver.find_element_by_id("kw").send_keys(search_string)
        driver.find_element_by_id("su").click()
        time.sleep(2)
        search_results = driver.find_element_by_xpath('//*[@id="1"]/h3/a').get_attribute('innerHTML')
        print(search_results)
        self.assertEqual(expect_string in search_results, True)
 
    def tearDown(self):
        self.driver.quit()
 
if __name__ == "__main__":
    unittest.main(verbosity=2)

在上述示例中,我创建了一个函数get_test_data() 用于获取我的测试数据。这个函数可以带参数,也可以不带参数,具体需要根据你的业务逻辑来。

注意:get_test_data() 的返回值,一定需要遵守ddt.data() 可接受的数据格式。

即:一组数据,每个数据为单个的值;多组数据,每组数据为一个列表或者一个字典。

关于 ddt 使用文件提供数据:JSON 和 YAML

我写在了另一篇文章
链接: 四外部导入

你可能感兴趣的:(python,开发语言)