python学习笔记之unittest

unittest单元测试框架不仅可以适用于单元测试,还可以适用接口测试、Web自动化测试等,它有一个很重要的特性:它是通过类(class)的方式,将测试用例组织在一起。

unittest框架核心要素

Unittest框架中最核心的四个概念是:test case, test suite, test runner, test fixture。
在这里插入图片描述

unittest框架常用模块

在这里插入图片描述

  • unittest.TestCase:TestCase类,所有测试用例类继承的基本类
  • unittest.TestSuite():unittest框架的TestSuite()类是用来创建测试套件的。
  • unittest.main(): 将一个单元测试模块变为可直接运行的测试脚本,main()方法使用TestLoader类来搜索所有包含在该模块中以“test”命名开头
    的测试方法,并自动执行他们,根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。
  • unittest.TextTestRunner(): unittest框架的TextTestRunner()类,通过该类下面的run()方法来运行suite所组装的测试用例,入参为suite测试套件。

unittest用法

  1. 导入unittest模块、被测文件或者其中的类
  2. 创建一个测试类,并继承unittest.TestCase
  3. 重写setUp和tearDown方法(如果有初始化条件和结束条件)
  4. 定义测试函数,函数以test_开头
  5. 在函数体中使用断言来判断测试结果是否符合预期结果
  6. 调用unittest.main()方法来运行测试用例
# 导入unittest模块
import unittest
from calculator import Calculator

# 定义测试类,父类为unittest.TestCase
class TestCalculator(unittest.TestCase):

    # 定义setUp()方法用于测试用例执行前的初始化工作
    # 所有类中方法的入参为self,定义方法的变量也要“self.变量”
    def setUp(self):
        print('test start')
        self.result = Calculator(10, 5)

    # 定义测试用例,以“test_”开头命名的方法,方法的入参为self
    # 可使用unittest.TestCase类下面的各种断言方法用于对测试结果的判断
    # 可定义多个测试用例

    def test_001_minus(self):
        """Test method minus(a, b)"""
        print('测试减法函数')
        self.assertEqual(self.result.minus(), 5, '计算错误!')


    # 定义tearDown()方法用于测试用例执行之后的善后工作。
    # 注意,方法的入参为self
    def tearDown(self):
        print('test end')


if __name__ == '__main__':
    # unittest.main()方法会搜索该模块下所有以test开头的测试用例方法,并自动执行它们。
    unittest.main(verbosity=2)

verbosity是一个选项,表示测试结果的信息复杂度,有0、1、2 三个值
0 (静默模式): 你只能获得总的测试用例数和总的结果 比如 总共10个 失败2 成功8
1 (默认模式): 非常类似静默模式 只是在每个成功的用例前面有个“.” 每个失败的用例前面有个 “F”
2 (详细模式):测试结果会显示每个测试用例的所有相关的信息
并且 你在命令行里加入不同的参数可以起到一样的效果
加入 --quiet 参数 等效于 verbosity=0
加入–verbose参数等效于 verbosity=2
什么都不加就是 verbosity=1

组织TestSuite

unittest执行测试用例,默认是根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。

import unittest

class MyTest(unittest.TestCase):
    def test_1(self):
        print('test_1')

    def test_2(self):
        print('test_2')

if __name__ == '__main__':
    suite = unittest.TestSuite()
    # 测试用例的执行顺序,按添加的顺序执行
    suite.addTest(MyTest('test_2'))
    suite.addTest(MyTest('test_1'))

    # 3. 运行容器中的测试用例
    runner = unittest.TextTestRunner()
    runner.run(suite)

TestLoader.loadTestsFromTestCase加载多个类

import unittest
from test_myclass1 import TestCalculator1
from test_myclass2 import TestCalculator2


if __name__ == '__main__':
    # 根据给定的测试类,获取其中所有以“test”开头的测试方法,并返回一个测试套件
    suite1 = unittest.TestLoader().loadTestsFromTestCase(TestCalculator1)
    suite2 = unittest.TestLoader().loadTestsFromTestCase(TestCalculator2)
    suite3 = unittest.TestLoader().loadTestsFromTestCase(TestCalculator2)

    # 将多个测试类加载到测试套件中
    # 通过调整suit2和suite1的顺序,可以设定执行顺序
    suite = unittest.TestSuite([suite1, suite2,suite3])

    # 设置verbosity = 2,可以打印出更详细的执行信息
    unittest.TextTestRunner(verbosity=2).run(suite)

TestLoader.discover方法匹配目录下的用例

假如现在目录下存在两个测试用例,Test_Myclass.py和Test_Myclass2.py,如果用addTests的方法添加
用例到测试套件,未免有点麻烦,这时候需要使用TestLoader()这个类。

import os
import unittest


if __name__ == '__main__':
    # 实例化测试套件对象
    suite = unittest.TestSuite()
    # 1.实例化TestLoader对象
    # 2.使用discover去找到一个目录下的所有测试用例
    loader = unittest.TestLoader()
    # 3.使用addTests将找到的测试用例放在测试套件下
    # os.getcwd()返回current working directory
    suite.addTests(loader.discover(os.getcwd()))

    # 或者另外一种写法
    test_dir = './test'
    suite = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')

    # 运行
    runner = unittest.TextTestRunner()
    runner.run(suite)

将运行结果输出到文件

     # 执行测试集合
     with open('UnittestTextReport.txt', 'a') as f:
        runner = unittest.TextTestRunner(stream=f, verbosity=2)
        runner.run(suite)

unittest常见用法

setUp和setDown

  • setUp() 和 tearDown() 两个方法(其实是重写了TestCase的这两个方法),这两个方法在每个测试方法执行前以及执行后执行一次,setUp用来为测试准备环境,tearDown用来清理环境。
  • 如果想要在所有case执行之前准备一次环境,并在所有case执行结束之后再清理环境,我们可以用setUpClass() 与 tearDownClass()。
    def setUp(self):
       print('test start')
       self.result = Calculator(10, 5) 

    def tearDown(self):
       print('test end')   

	@classmethod
    def setUpClass(cls):
        print('仅测试套件前执行一次')

    @classmethod
    def tearDownClass(cls):
        print('仅测试套件结束后执行一次')

跳过某个Case

如果我们临时想要跳过某个case不执行怎么办?unittest也提供了两种方法:
1 skip装饰器

  • @unittest.skip(reason): skip(reason)装饰器:无条件跳过装饰的测试,并说明跳过测试的原因。
  • @unittest.skipIf(reason): skipIf(condition,reason)装饰器:条件为真时,跳过装饰的测试,并说明跳过测试的原因。
  • @unittest.skipUnless(reason): skipUnless(condition,reason)装饰器:条件为假时,跳过装饰的测试,并说明跳过测试的
    原因。
  • @unittest.expectedFailure(): expectedFailure()测试标记为失败。
    @unittest.skip("I don't want to run this case.")
    def test_add(self):
        """Test method add(a, b)"""
        print('测试加法函数')
        self.assertEqual(self.result.add(), 15, '计算错误!')

    @unittest.skipIf(3 > 2, "3大于2,此用例不执行")
    def test_minus(self):
        """Test method minus(a, b)"""
        print('测试减法函数')
        self.assertEqual(self.result.minus(), 5, '计算错误!')

    # 除非是linux平台,否则忽略此方法,win32是windows平台
    @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
    def test_skip(self):
        """Test method skip(a, b)"""
        print('测试跳过函数')
        self.assertEqual(self.result.divide(), 2, '计算错误!')

2、TestCase.skipTest()方法

    def test_multip(self):
        """Test method multi(a, b)"""

		# 跳过
        self.skipTest('Do not run this.')
        print('测试乘法函数')
        self.assertEqual(self.result.multip(), 50, '计算错误!')

Unittest常见用法:断言方法

  • assertEqual(a,b,[msg=‘失败时打印的信息’]):断言a,b是否相等,相等则用例通过。
  • assertNotEqual(a,b,[msg=‘失败时打印的信息’]):断言a,b是否相等,不相等则试用例通过。
  • assertTrue(x,[msg=‘失败时打印的信息’]):断言x是否True,是True则用例通过。
  • assertFalse(x,[msg=‘失败时打印的信息’]):断言x是否False,是False则用例通过。
  • assertIs(a,b,[msg=‘失败时打印的信息’]):断言a是否是b,是则用例通过。
  • assertNotIs(a,b,[msg=‘失败时打印的信息’]):断言a是否是b,不是则用例通过。
  • assertIsNone(x,[msg=‘失败时打印的信息’]):断言x是否None,是None则用例通过。
  • assertIsNotNone(x,[msg=‘失败时打印的信息’]):断言x是否None,不是None则用例通过。
  • assertIn(a,b,[msg=‘失败时打印的信息’]):断言a是否在b中,在b中则用例通过。
  • assertNotIn(a,b,[msg=‘失败时打印的信息’]):断言a是否在b中,不在b中则用例通过。
  • assertIsInstance(a,b,[msg=‘失败时打印的信息’]):断言a是b的一个实例,是则用例通过。
  • assertNotIsInstance(a,b,[msg=‘失败打印的信息’]):断言a不是b的一个实例,不是则用例过。
import unittest, random


# 被测试类
class MyClass(object):

    @classmethod
    def sum(cls, a, b):
        return a + b

    @classmethod
    def div(cls, a, b):
        return a / b

    @classmethod
    def retrun_None(cls):
        return None


# 单元测试类
class MyTest(unittest.TestCase):

    # assertEqual()方法实例
    def test_assertEqual(self):
        # 断言两数之和的结果
        try:
            a, b = 1, 2
            sum = 3
            self.assertEqual(a + b, sum, '断言失败,%s + %s != %s' % (a, b, sum))
        except AssertionError as e:
            print(e)

    # assertNotEqual()方法实例
    def test_assertNotEqual(self):
        # 断言两数之差的结果
        try:
            a, b = 5, 2
            res = 1
            self.assertNotEqual(a - b, res, '断言失败,%s - %s != %s' % (a, b, res))
        except AssertionError as e:
            print(e)

    # assertTrue()方法实例
    def test_assertTrue(self):
        # 断言表达式的为真
        try:
            self.assertTrue(1 == 1, "表达式为假")
        except AssertionError as e:
            print(e)

    # assertFalse()方法实例
    def test_assertFalse(self):
        # 断言表达式为假
        try:
            self.assertFalse(3 == 2, "表达式为真")
        except AssertionError as e:
            print(e)

    # assertIs()方法实例
    def test_assertIs(self):
        # 断言两变量类型属于同一对象
        try:
            a = 12
            b = a
            self.assertIs(a, b, "%s与%s不属于同一对象" % (a, b))
        except AssertionError as e:
            print(e)

    # test_assertIsNot()方法实例
    def test_assertIsNot(self):
        # 断言两变量类型不属于同一对象
        try:
            a = 12
            b = "test"
            self.assertIsNot(a, b, "%s与%s属于同一对象" % (a, b))
        except AssertionError as  e:
            print(e)

    # assertIsNone()方法实例
    def test_assertIsNone(self):
        # 断言表达式结果为None
        try:
            result = MyClass.retrun_None()
            self.assertIsNone(result, "not is None")
        except AssertionError as e:
            print(e)

    # assertIsNotNone()方法实例
    def test_assertIsNotNone(self):
        # 断言表达式结果不为None
        try:
            result = MyClass.sum(2, 5)
            self.assertIsNotNone(result, "is None")
        except AssertionError as e:
            print(e)

    # assertIn()方法实例
    def test_assertIn(self):
        # 断言对象A是否包含在对象B中
        try:
            strA = "this is a test"
            strB = "is"
            self.assertIn(strB, strA, "%s不包含在%s中" % (strB, strA))
        except AssertionError as e:
            print(e)

    # assertNotIn()方法实例
    def test_assertNotIn(self):
        # 断言对象A不包含在对象B中
        try:
            strA = "this is a test"
            strB = "Selenium"
            self.assertNotIn(strB, strA, "%s包含在%s中" % (strB, strA))
        except AssertionError as e:
            print(e)

    # assertIsInstance()方法实例
    def test_assertIsInstance(self):
        # 测试对象A的类型是否值指定的类型
        try:
            x = MyClass
            y = object
            self.assertIsInstance(x, y, "%s的类型不是%s" % (x, y))
        except AssertionError as e:
            print(e)

    # assertNotIsInstance()方法实例
    def test_assertNotIsInstance(self):
        # 测试对象A的类型不是指定的类型
        try:
            a = 123
            b = str
            self.assertNotIsInstance(a, b, "%s的类型是%s" % (a, b))
        except AssertionError as e:
            print(e)

if __name__ == '__main__':
    # 执行单元测试
    unittest.main()

Unittest常见用法:命令行执行用例方法

unittest 支持用例自动(递归)发现:

1、默认发现当前目录下所有符合 test*.py 测试用例
使用 python -m unittest 或 python -m unittest discover
2、通过 -s 参数指定要自动发现的目录, -p 参数指定用例文件的名称模式
python -m unittest discover -s project_directory -p “test_*.py”

3、通过位置参数指定自动发现的目录和用例文件的名称模式
python -m unittest discover project_directory “test_*.py”

unittest 支持执行指定用例:

1、指定测试模块
python -m unittest test_module1 test_module2
2、指定测试类
python -m unittest test_module.TestClass
3、指定测试方法
python -m unittest test_module.TestClass.test_method
4、指定测试文件路径(仅 Python 3)
python -m unittest tests/test_something.py

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值