2.3.5 数据驱动模式

数据驱动测试通过从数据文件获取输入数据,控制测试用例的执行。在unittest框架中,可以通过ParamUnittest、Parameterized和DDT模块实现参数化。ParamUnittest仅能类参数化,Parameterized支持类、方法、函数参数化,DDT则能处理多种类型的数据结构,包括从文件读取数据。示例代码来源于官方文档,提倡学习查找和分析模块API。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据驱动

       数据驱动从数据文件读取输入数据,通过变量的参数化将测试数据传入测试脚本,不同的数据文件对应不同的测试用例,数据和脚本分离。数据来控制测试的业务流。比如你测一个WEB程序,有很多页面,你可以通过一个数据来控制每次是再哪个页面下工作的(即通过数据来导航到相应的页面)。它是关键字驱动的低级版本,他控制的是函数级的,而关键字是控制动作级的。所以数据驱动应该是可以控制整个测试的。

 

Unittest框架参数化

       如果一个业务需要通过多组数据进行完成测试的话,那么一个测试类中肯定会涉及多个测试用例,且每个测试用例会存在重复的操作,那么此时肯定是效率不佳且走读性不好;当然此时肯定会有同学思考到使用循环,但是如何通过循环进行控制对象创建,如何控制用例执行呢?所以肯定不能够使用循环解决,必然此时需要借助unittest框架中的参数化完成。

       在unittest框架中并没有直接提供参数化的实现方式,而是需要通过第三方模块进行完成;

 

A.ParamUnittest模块:该模块主要实现unittest框架的参数化,并且是装饰在类上;

  • 缺点:不能够单独针对其中某一个测试方法进行装饰参数化,在实现参数化时必须只定义一个测试方法;

  • 代码示例如下:

import unittestimport paramunittest
@paramunittest.parametrized(    ('1', '2'),    #(4, 3),    ('2', '3'),    (('4', ), {'b': '5'}),    ((), {'a': 5, 'b': 6}),    {'a': 5, 'b': 6},)class TestFoo(paramunittest.ParametrizedTestCase):    def setParameters(self, a, b):        self.a = a        self.b = b
    def testLess(self):        self.assertLess(self.a, self.b)
@paramunittest.parametrized(    ('1', '2'),    #(4, 3),    ('2', '3'),    (('4', ), {'b': '5'}),    ((), {'a': 5, 'b': 6}),    {'a': 5, 'b': 6},)class TestBar(unittest.TestCase):    def setParameters(self, a, b):        self.a = a        self.b = b
    def testLess(self):        self.assertLess(self.a, self.b)

 

B.Parameterized模块:可以应用于多个自动化测试框架:nose框架、unittest框架、pytest框架;该模块不仅可以用于进行装饰类参数化,还可以装饰方法参数化,且还可以装饰函数参数化;后期的pytest框架的参数化也是需要使用该模块完成;

  • 如果是函数参数化的话则直接使用parameterized装饰器

  • 如果是方法参数化的话则需要使用parameterized调用expand方法进行装饰

  • 如果是类参数化的话则需要使用parameterized_class装饰器

  • 示例代码如下:

from nose.tools import assert_equalfrom parameterized import parameterized, parameterized_class
import unittestimport math
@parameterized([    (2, 2, 4),    (2, 3, 8),    (1, 9, 1),    (0, 9, 0),])def test_pow(base, exponent, expected):   assert_equal(math.pow(base, exponent), expected)
class TestMathUnitTest(unittest.TestCase):   @parameterized.expand([       ("negative", -1.5, -2.0),       ("integer", 1, 1.0),       ("large fraction", 1.6, 1),   ])   def test_floor(self, name, input, expected):       assert_equal(math.floor(input), expected)
@parameterized_class(('a', 'b', 'expected_sum', 'expected_product'), [   (1, 2, 3, 2),   (5, 5, 10, 25),])class TestMathClass(unittest.TestCase):   def test_add(self):      assert_equal(self.a + self.b, self.expected_sum)
   def test_multiply(self):      assert_equal(self.a * self.b, self.expected_product)
@parameterized_class([   { "a": 3, "expected": 2 },   { "b": 5, "expected": -4 },])class TestMathClassDict(unittest.TestCase):   a = 1   b = 1
   def test_subtract(self):      assert_equal(self.a - self.b, self.expected)

C.DDT模块(Data Driven Test数据驱动测试):表示的是可以实现多种类型参数化的数据结构传入(前面的两种形式主要是以容器型的数据类型传入为主,可以装饰在类、函数、方法上); 

  • a.单一型数据结构:无论传入的数据是何种类型,都当做一个值处理; 

  • b.复合数据类型结构处理(list、tuple、dict):如果需要针对这些类型的数据分别对应参数的话则必须添加一个装饰器,@ddt.unpack    

  • c.可以直接读取数据格式文件中的数据进行参数化;

  • 示例代码如下:

@ddtclass FooTestCase(unittest.TestCase):    def test_undecorated(self):        self.assertTrue(larger_than_two(24))
    @data(3, 4, 12, 23)    def test_larger_than_two(self, value):        self.assertTrue(larger_than_two(value))
    @data(1, -3, 2, 0)    def test_not_larger_than_two(self, value):        self.assertFalse(larger_than_two(value))
    @data(annotated(2, 1), annotated(10, 5))    def test_greater(self, value):        a, b = value        self.assertGreater(a, b)
    @data(annotated2([2, 1], 'Test_case_1', """Test docstring 1"""),          annotated2([10, 5], 'Test_case_2', """Test docstring 2"""))    def test_greater_with_name_docstring(self, value):        a, b = value        self.assertGreater(a, b)        self.assertIsNotNone(getattr(value, "__name__"))        self.assertIsNotNone(getattr(value, "__doc__"))
    @file_data('data/test_data_dict_dict.json')    def test_file_data_json_dict_dict(self, start, end, value):        self.assertLess(start, end)        self.assertLess(value, end)        self.assertGreater(value, start)
    @file_data('data/test_data_dict.json')    def test_file_data_json_dict(self, value):        self.assertTrue(has_three_elements(value))
    @file_data('data/test_data_list.json')    def test_file_data_json_list(self, value):        self.assertTrue(is_a_greeting(value))
    @needs_yaml    @file_data('data/test_data_dict_dict.yaml')    def test_file_data_yaml_dict_dict(self, start, end, value):        self.assertLess(start, end)        self.assertLess(value, end)        self.assertGreater(value, start)
    @needs_yaml    @file_data('data/test_data_dict.yaml')    def test_file_data_yaml_dict(self, value):        self.assertTrue(has_three_elements(value))
    @needs_yaml    @file_data('data/test_data_list.yaml')    def test_file_data_yaml_list(self, value):        self.assertTrue(is_a_greeting(value))
    @data((3, 2), (4, 3), (5, 3))    @unpack    def test_tuples_extracted_into_arguments(self, first_value, second_value):        self.assertTrue(first_value > second_value)
    @data([3, 2], [4, 3], [5, 3])    @unpack    def test_list_extracted_into_arguments(self, first_value, second_value):        self.assertTrue(first_value > second_value)
    @unpack    @data({'first': 1, 'second': 3, 'third': 2},          {'first': 4, 'second': 6, 'third': 5})    def test_dicts_extracted_into_kwargs(self, first, second, third):        self.assertTrue(first < third < second)
    @data(u'ascii', u'non-ascii-\N{SNOWMAN}')    def test_unicode(self, value):        self.assertIn(value, (u'ascii', u'non-ascii-\N{SNOWMAN}'))
    @data(3, 4, 12, 23)    def test_larger_than_two_with_doc(self, value):        """Larger than two with value {0}"""        self.assertTrue(larger_than_two(value))
    @data(3, 4, 12, 23)    def test_doc_missing_args(self, value):        """Missing args with value {0} and {1}"""        self.assertTrue(larger_than_two(value))
    @data(3, 4, 12, 23)    def test_doc_missing_kargs(self, value):        """Missing kargs with value {value} {value2}"""        self.assertTrue(larger_than_two(value))
    @data([3, 2], [4, 3], [5, 3])    @unpack    def test_list_extracted_with_doc(self, first_value, second_value):        """Extract into args with first value {} and second value {}"""        self.assertTrue(first_value > second_value)

以上示例均来源于官网,所以大家一定要学会如何查找对应模块的API,学会分析其模块中的示例。

最后CRM系统封装的三大类型参数化的代码,部分截图:

可回复【unittest参数化】获取全套代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zemuerqi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值