一、Python数据驱动工具ddt

1、  安装

ddt pip install ddt

DDT是 “Data-Driven Tests”的缩写

 资料:http://ddt.readthedocs.io/en/latest/

2、  DDT的使用

(1)   ddt.ddt:

装饰类,也就是继承自TestCase的类

(2)   ddt.data:

装饰测试方法。参数是一系列的值。

(3)   ddt.file_data:

装饰测试方法。参数是文件名。文件可以是json 或者 yaml类型。

注意,如果文件以”.yml”或者”.yaml”结尾,ddt会作为yaml类型处理,其他所有文件都会作为json文件处理。

如果文件中是列表,每个列表的值会作为测试用例参数,同时作为测试用例方法名后缀显示。如果文件中是字典,字典的key会作为测试用例方法的后缀显示,字典的值会作为测试用例参数。

(4)   ddt.unpack:

传递的是复杂的数据结构时使用。比如使用元组或者列表,添加unpack之后,ddt会自动把元组或者列表对应到多个参数上。字典也可以这样处理。

(5)   测试用例方法名生成规则

使用ddt后,会产生一个新的测试用例方法名:之前的测试用例方法名_ordinal_data

之前的测试用例方法名:即定义的测试用例方法名。比如def test_large(),这里就是test_large

ordinal:整数,从1开始递加。

 data:如果传递过来的数据存在__name__属性,则这里就是该数据的__name__值。如果未定义__name__属性,ddt会尽量将传递过来的数据转化为python标识符,作为data显示。比如(3,2)就转化为3_2。需要注意的是,如果数据是字典,则这里就是字典的key。

 

 二、实例演示

 

1、@ddt.ddt&&@ddt.data

main.py:
from selenium import webdriver
import unittest, time
import logging, traceback
import ddt
from selenium.common.exceptions import NoSuchElementException

# 初始化日志对象
logging.basicConfig(
    # 日志级别
    level = logging.INFO,
    # 日志格式
    # 时间、代码所在文件名、代码行号、日志级别名字、日志信息
    format = '%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
    # 打印日志的时间
    datefmt = '%a, %d %b %Y %H:%M:%S',
    # 日志文件存放的目录(目录必须存在)及日志文件名
    filename = 'e:/report.log',
    # 打开日志文件的方式
    filemode = 'w'
)

@ddt.ddt
class TestDemo(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Ie(executable_path = "c:\\IEDriverServer")
    @ddt.data([u"神奇动物在哪里", u"叶茨"],
              [u"疯狂动物城", u"古德温"],
              [u"大话西游之月光宝盒", u"周星驰"])
    @ddt.unpack   #解包,将测试数据对应到testdata 和 expectdata
    def test_dataDrivenByObj(self, testdata, expectdata):
        url = "http://www.baidu.com"
        # 访问百度首页
        self.driver.get(url)
        # 设置隐式等待时间为10秒
        self.driver.implicitly_wait(10)
        try:
            # 找到搜索输入框,并输入测试数据
            self.driver.find_element_by_id("kw").send_keys(testdata)
            # 找到搜索按钮,并点击
            self.driver.find_element_by_id("su").click()
            time.sleep(3)
            # 断言期望结果是否出现在页面源代码中
            self.assertTrue(expectdata in self.driver.page_source)
        except NoSuchElementException, e:
            logging.error(u"查找的页面元素不存在,异常堆栈信息:" \
                          + str(traceback.format_exc()))
        except AssertionError, e:
            logging.info(u"搜索“%s”,期望“%s”,失败" %(testdata, expectdata))
        except Exception, e:
            logging.error(u"未知错误,错误信息:" + str(traceback.format_exc()))
        else:
            logging.info(u"搜索“%s”,期望“%s”通过" %(testdata, expectdata))

    def tearDown(self):
        self.driver.quit()

if __name__ == '__main__':
    unittest.main()

 

2、@ddt.file_data

test_data_list.json:
[
        "邓肯||蒂姆",
        "乔丹||迈克尔",
        "库里||斯蒂芬",
        "杜兰特||凯文",
        "詹姆斯||勒布朗"
    ]

main.py:

from selenium import webdriver
import unittest, time
import logging, traceback
import ddt
from ReportTemplate import htmlTemplate
from selenium.common.exceptions import NoSuchElementException

#如果有no json的报错信息,请将json文件存储为utf-8,with Bom
# 初始化日志对象
logging.basicConfig(
    # 日志级别
    level = logging.INFO,
    # 日志格式
    # 时间、代码所在文件名、代码行号、日志级别名字、日志信息
    format = '%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
    # 打印日志的时间
    datefmt = '%a, %Y-%m-%d %H:%M:%S',
    # 日志文件存放的目录(目录必须存在)及日志文件名
    filename = 'e:/report.log',
    # 打开日志文件的方式
    filemode = 'w'
)

@ddt.ddt
class TestDemo(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        # 整个测试过程只被调用一次
        TestDemo.trStr = ""

    def setUp(self):
        self.driver = webdriver.Ie(executable_path = "c:\\IEDriverServer")
        status = None # 用于存放测试结果状态,失败'fail',成功'pass'
        flag = 0 # 数据驱动测试结果的标志,失败置0,成功置1

    @ddt.file_data("test_data_list.json")
    def test_dataDrivenByFile(self, value):
        # 决定测试报告中状态单元格中内容的颜色
        flagDict = {0: 'red', 1: '#00AC4E'}

        url = "http://www.baidu.com"
        # 访问百度首页
        self.driver.get(url)
        # 将浏览器窗口最大化
        self.driver.maximize_window()
        print value
        # 将从.json文件中读取出的数据用“||”进行分隔成测试数据
        # 和期望数据
        testdata, expectdata = tuple(value.strip().split("||"))
        # 设置隐式等待时间为10秒
        self.driver.implicitly_wait(10)

        try:
            # 获取当前的时间戳,用于后面计算查询耗时用
            start = time.time()
            # 获取当前时间的字符串,表示测试开始时间
            startTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            # 找到搜索输入框,并输入测试数据
            self.driver.find_element_by_id("kw").send_keys(testdata)
            # 找到搜索按钮,并点击
            self.driver.find_element_by_id("su").click()
            time.sleep(3)
            # 断言期望结果是否出现在页面源代码中
            self.assertTrue(expectdata in self.driver.page_source)
        except NoSuchElementException, e:
            logging.error(u"查找的页面元素不存在,异常堆栈信息:" \
                          + str(traceback.format_exc()))
            status = 'fail'
            flag = 0
        except AssertionError, e:
            logging.info(u"搜索“%s”,期望“%s”,失败" %(testdata, expectdata))
            status = 'fail'
            flag = 0
        except Exception, e:
            logging.error(u"未知错误,错误信息:" + str(traceback.format_exc()))
            status = 'fail'
            flag = 0
        else:
            logging.info(u"搜索“%s”,期望“%s”通过" %(testdata, expectdata))
            status = 'pass'
            flag = 1
        # 计算耗时,从将测试数据输入到输入框中到断言期望结果之间所耗时
        wasteTime = time.time() - start - 3 # 减去强制等待的3秒
        # 每一组数据测试结束后,都将其测试结果信息插入表格行
        # 的HTML代码中,并将这些行HTML代码拼接到变量trStr变量中,
        # 等所有测试数据都被测试结束后,传入htmlTemplate()函数中
        # 生成完整测试报告的HTML代码
        TestDemo.trStr += u'''
        <tr>
            <td>%s</td>
            <td>%s</td>
            <td>%s</td>
            <td>%.2f</td>
            <td style="color:%s">%s</td>
        </tr><br />''' % (testdata, expectdata,startTime,  wasteTime, flagDict[flag], status)

    def tearDown(self):
        self.driver.quit()

    @classmethod
    def tearDownClass(cls):
        # 写自定义的html测试报告
        # 整个测试过程只被调用一次
        htmlTemplate(TestDemo.trStr)

if __name__ == '__main__':
    unittest.main()