自动化测试之————UnitTest框架

UnitTest框架



一、认识UnitTest框架

unittest 是 Python标准库中的一个测试框架,用于编写和运行单元测试。它提供了一些类和方法,用于组织测试用例、运行测试并获取结果,使用 unittest编写和运行测试用例可以帮助我们自动化测试过程,并确保代码的正确性和鲁棒性

UnitTest是Python⾃带的⼀个单元测试框架,⽤它来做单元测试

1.1 为什么使用UnitTest

  1. 能够组织多个⽤例去执⾏
  2. 提供丰富的断⾔⽅法(让程序代码代替⼈⼯⾃动的判断预期结果和实际结果是否相符)
  3. 能够⽣成测试报告

1.2 如何使用UnitTest

unittest 是 Python 的标准库,不需要额外安装。在你安装 Python 程序时,unittest 库就已经存在了,直接导入即可

import unittest

1.3 UnitTest的五大核心要素

测试用例(Test Cases):测试用例是描述要测试的特定功能或行为的代码块。每个测试用例都是一个独立的功能单元,可以针对不同的输入和条件进行测试

测试套件(Test Suites):测试套件是将多个测试用例组合在一起的容器,供批量运行和管理。可以使用 unittest.TestSuite() 类来创建一个测试套件,并将测试用例添加到其中

测试运行器(Test Runner):测试运行器是执行测试用例和报告测试结果的组件。unittest 提供了多种运行器,如 TextTestRunner、HTMLTestRunner 等,可以根据需要选择适当的运行器

测试加载(TestLoader):测试加载是指如何将测试用例组织和加载到测试套件中以进行执行

测试装置(Test Fixtures):测试装置是用于测试环境的准备和清理的代码块。它包括 setUp() 和 tearDown() 方法,在每个测试用例执行前后分别调用,用于设置和清理测试环境,以确保每个测试用例都在相同的环境中运行

二、TestCase(测试用例)

  1. 是⼀个代码⽂件, 在代码⽂件中 来书写真正的⽤例代码
  2. 代码⽂件的名字必须按照标识符的规则来书写(可以将代码的作⽤在⽂件的开头使⽤注释说明)

步骤

  1. 导包 (unittest)
  2. ⾃定义测试类
  3. 在测试类中书写测试⽅法
  4. 执⾏⽤例
# 导包
import unittest

# 自定义测试类
class MyTestCase(unittest.TestCase):
    def setUp(self):
        # 在每个测试用例之前执行的操作
        pass

    def tearDown(self):
        # 在每个测试用例之后执行的操作
        pass

# 书写要求, 测试⽅法 必须以 test_ 开头(本质是以test 开头)
    def test_addition(self):
        self.assertEqual(2 + 2, 4)

    def test_subtraction(self):
        self.assertEqual(5 - 3, 2)

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

在上述示例中,MyTestCase 类继承自 unittest.TestCase
并定义了两个测试方法 test_addition 和 test_subtraction
在每个测试方法中,使用了断言方法来验证期望结果和实际结果是否相等
setUp() 和 tearDown() 方法是可选的
可以根据需要在测试前后执行一些准备和清理操作
通过运行 unittest.main(),将执行所有继承自 TestCase 的测试用例,并生成测试报告


三、 TestSuite(测试套件)与TestRunner(测试运行)

测试套件(Test Suite)是用于容纳和管理多个测试用例的对象。通过将多个测试用例组合到测试套件中,可以方便地批量执行和管理测试

步骤

  1. 导包(unittest)
  2. 实例化(创建对象)套件对象
  3. 使⽤套件对象添加⽤例⽅法
  4. 实例化运⾏对象
  5. 使⽤运⾏对象去执⾏套件对象
# 1. 导包(unittest)
import unittest

class MyTestCase(unittest.TestCase):
    def test_addition(self):
        self.assertEqual(2 + 2, 4)

    def test_subtraction(self):
        self.assertEqual(5 - 3, 2)

if __name__ == '__main__':
	# 2. 实例化(创建对象)套件对象
    suite = unittest.TestSuite()
    # 3. 使⽤套件对象添加⽤例⽅法
    suite.addTest(MyTestCase('test_addition'))
    suite.addTest(MyTestCase('test_subtraction'))
	# 4. 实例化运⾏对象
    runner = unittest.TextTestRunner()
    # 5. 使⽤运⾏对象去执⾏套件对象
    runner.run(suite)

在上述示例中,我们创建了一个测试套件 suite
并将两个测试用例 test_addition 和 test_subtraction 添加到测试套件中
然后,我们使用 TextTestRunner 运行了测试套件
并生成了一个简单的文本测试报告


三、TestLoader(测试加载)

测试加载是指将测试用例加载到测试套件中的过程
测试加载的目的是将要执行的测试用例组织成一个测试套件,以便后续执行和生成测试报告

步骤

  1. 导包
  2. 实例化测试加载对象并添加用例 —> 得到的是 suite 对象
  3. 实例化 运行对象
  4. 运行对象执行套件对象

在一个项目中 TestCase(测试用例) 的代码,一般放在一个单独的目录 (case)
写法:suite = unittest.defaultTestLoader.discover(“指定搜索的目录文件”,“指定字母开头模块文件”)

# 1. 导包
# 2. 使用默认的加载对象并加载用例
# 3. 实例化运行对象并运行
"""TestLoader 的使用"""
# 1, 导包
import unittest
# 2, 使用默认的加载对象并加载用例
suite = unittest.defaultTestLoader.discover('case', 'hm_*.py')
# 可以将 3 4 步 变为一步
unittest.TextTestRunner().run(suite)

四、Fixture(测试夹具)

测试夹具(test fixture)是指在测试用例执行前后设置和清理测试环境所需的代码。夹具可以确保每个测试用例在独立的环境中执行,以避免测试用例之间相互影响

4.1 方法级别

setUp()和tearDown()方法:

  • setUp()方法在每个测试用例执行之前调用,用于设置测试环境
  • tearDown()方法在每个测试用例执行之后调用,用于清理测试环境
# 方法执行之前
def setUp(self):
每个测试方法执行之前都会执行
pass
# 方法执行之后
def tearDown(self):
每个测试方法执行之后都会执行
pass

4.2 类级别

  • setUpClass()方法在测试类中的所有测试用例执行之前调用一次,用于设置整个测试类的环境
  • tearDownClass()方法在测试类中的所有测试用例执行之后调用一次,用于清理整个测试类的环境
  • 这两个方法需要使用@classmethod装饰器进行修饰
import unittest

class MyTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        # 在测试类中的所有测试用例执行之前的准备工作
        cls.data = [1, 2, 3]

    @classmethod
    def tearDownClass(cls):
        # 在测试类中的所有测试用例执行之后的清理工作
        cls.data = None

    def test_something(self):
        # 测试用例
        self.assertEqual(len(self.data), 3)

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

五、断言

断言(assertion)是在测试代码中用于检查是否满足特定条件的语句。它们用于验证预期结果与实际结果是否一致,从而确定测试是否通过

断言的结果有两种:

True, 用例通过
False, 代码抛出异常, 用例不通过
在 unittest 中使用断言, 都需要通过 self.断言方法 来试验

断言方法:
assertEqual(a, b):断言a和b是否相等

self.assertEqual(2 + 2, 4)  # 断言2+2是否等于4

assertNotEqual(a, b):断言a和b是否不相等

self.assertNotEqual(2 + 2, 5)  # 断言2+2是否不等于5

assertTrue(x):断言x是否为True

self.assertTrue(2 < 3)  # 断言2是否小于3,结果为True

assertFalse(x):断言x是否为False

self.assertFalse(2 > 3)  # 断言2是否大于3,结果为False

assertIs(a, b):断言a和b是否是同一个对象

self.assertIs(value1, value2)  # 断言value1和value2是否是同一个对象

assertIsNot(a, b):断言a和b是否不是同一个对象

self.assertIsNot(value1, value2)  # 断言value1和value2是否不是同一个对象

assertIn(a, b):用于断言a是否存在于b中

self.assertIn(item, list)  # 断言item是否存在于list中
import unittest

class Calculator:
    def add(self, a, b):
        return a + b

class TestCalculator(unittest.TestCase):
    """测试计算器功能"""

    def setUp(self):
        self.calculator = Calculator()

    def tearDown(self):
        pass

    def test_addition(self):
        """测试加法"""
        result = self.calculator.add(2, 3)
        self.assertEqual(result, 5)

    def test_invalid_input(self):
        """测试无效输入"""
        with self.assertRaises(TypeError):
            self.calculator.add('2', 3)

if __name__ == '__main__':
    unittest.main()
  • 在上述示例中,我们首先定义了一个简单的Calculator类

  • 该类仅具有一个add方法,用于执行加法操作

  • 然后,我们编写了一个名为TestCalculator的测试类,继承自unittest.TestCase

  • 在该测试类中,我们定义了两个测试方法test_addition和test_invalid_input

  • 分别用于测试加法操作的正确性和处理无效输入的情况

  • 在每个测试方法之前,我们使用setUp方法在测试之前创建了一个Calculator实例

  • 并在tearDown方法中进行清理工作

  • 这可以确保每个测试方法在独立的环境中运行,防止测试之间相互影响

请注意,assertRaises方法用于检测是否引发了特定的异常。在test_invalid_input方法中,我们使用了该方法来检查在给定无效输入的情况下是否引发了TypeError异常

六、跳过

对于一些未完成的或者不满足测试条件的测试函数和测试类, 不想执行,可以使用跳过
使用方法, 装饰器完成
代码书写在 TestCase 文件

# 直接将测试函数标记成跳过
@unittest.skip('跳过额原因')
# 根据条件判断测试函数是否跳过 , 判断条件成立, 跳过
@unittest.skipIf(判断条件, '跳过原因')
import unittest

class MyTestCase(unittest.TestCase):
    def test_example(self):
        self.assertEqual(2 + 2, 4)

    @unittest.skip("示例跳过")
    def test_skip_example(self):
        self.assertEqual(2 * 2, 5)

    @unittest.skipIf(True, "条件为 True,跳过")
    def test_skip_if_example(self):
        self.assertEqual(2 / 0, 1)

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

在上面的示例中,我们定义了三个测试方法
test_example 方法是一个正常的测试用例,不会被跳过

test_skip_example 方法上使用了 @unittest.skip 装饰器,因此它被标记为跳过,不会执行

test_skip_if_example 方法上使用了 @unittest.skipIf 装饰器,并且设置了条件为 True
因此,这个测试用例会根据条件是否满足来决定是否被跳过
在这个示例中,条件为 True,所以这个测试用例也会被跳过


七、参数化

参数化 在测试方法中, 使用 变量 来代替具体的测试数据, 然后使用传参的方法将测试数据传递给方法的变量
好处: 相似的代码不需要多次书写

安装插件
联网安装(在 cmd 窗口安装 或者 )
pip install parameterized

可以使用 @unittest.parameterized.parameterized 装饰器来实现参数化测试

  1. 导包 unittest/ pa
  2. 定义测试类
  3. 书写测试方法(用到的测试数据使用变量代替)
  4. 组织测试数据并传参
import unittest
from parameterized import parameterized

class Calculator:
    def add(self, a, b):
        return a + b

class TestCalculator(unittest.TestCase):
    """测试计算器功能"""

    @parameterized.expand([
        (2, 3, 5),
        (0, 0, 0),
        (-1, 4, 3),
        (10, -5, 5)
    ])
    def test_addition(self, a, b, expected_result):
        """测试加法"""
        calculator = Calculator()
        result = calculator.add(a, b)
        self.assertEqual(result, expected_result)

if __name__ == '__main__':
    unittest.main()
  • 示例中,我们首先定义了一个 Calculator 类,其中有一个 add 方法用于执行加法运算
  • 然后,在 TestCalculator 类中,我们对 test_addition 方法进行了参数化
  • 我们使用 @parameterized.expand 装饰器来指定参数化的数据集
  • 数据集是一个列表,其中每个元素代表一个测试案例的参数组合
  • 而在每个元素内部,我们可以指定多个参数值,以及期望的结果值
  • 在 test_addition 方法的参数列表中,我们定义了三个参数 a、b 和 expected_result
  • 并且它们会按照数据集中的顺序进行传

八、测试报告

1、自带的测试报告

只有单独运行 TestCase 的代码,才会生成测试报告

2、生成第三方的测试报告

  1. 获取第三方的 测试运行类模块 , 将其放在代码的目录中
  2. 导包 unittest
  3. 使用 套件对象, 加载对象 去添加用例方法
  4. 实例化 第三方的运行对象 并运行 套件对象

当我们使用 HTMLTestRunner 生成 HTML 格式的测试报告时,需要下载 HTMLTestRunner 插件并导入它,然后通过创建测试套件并运行测试来生成测试报告

import unittest
from HTMLTestRunner import HTMLTestRunner

class MyTestCase(unittest.TestCase):
    def test_example(self):
        self.assertEqual(2 + 2, 4)

    def test_another_example(self):
        self.assertEqual(3 * 3, 9)

if __name__ == '__main__':
    # 创建测试套件
    suite = unittest.TestSuite()
    suite.addTest(MyTestCase('test_example'))
    suite.addTest(MyTestCase('test_another_example'))

    # 指定报告文件路径
    report_file = 'test_report.html'

    # 使用 HTMLTestRunner 运行测试并生成报告
    with open(report_file, 'wb') as f:
        runner = HTMLTestRunner(stream=f, title='测试报告', description='执行结果如下:')
        runner.run(suite)
  • 在这个示例中,我们定义了两个测试方法 test_example 和 test_another_example
  • 然后,我们创建了一个测试套件 suite,并将这两个测试方法添加到套件中
  • 接下来,我们指定了报告文件的路径 report_file,这里设置为 test_report.html
  • 然后,我们使用 HTMLTestRunner 运行测试并生成报告
  • 我们通过 open 函数打开文件并将其作为参数传递给 HTMLTestRunner 的 stream 参数
  • 这样生成的报告将会被写入到这个文件中
  • title 参数用于设置报告的标题,description 参数用于设置报告的描述
  • 最后,我们运行测试套件,并将测试结果生成为 HTML 格式的报告
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值