单元测试框架 unittest 复习

测试:在规定的条件下对软件进行操作,发现软件存在的逻辑,功能,性能等问题
测试过程:单元测试–集成测试–系统测试–性能测试


单元测试:对软件设计最小单元进行正确性检测的测试,发现可能存在的问题。
单元测试的目的:就是发现模块内部的逻辑,语法,算法等错误。
单元测试方式代码级别测试模块功能测试。
代码级别测试:
接口测试:确保模块接口实现正确,符合设计文档规范或者约定。
数据结构测试:确保数据结构可用,数据库、文件、自定义数据结构;
边界测试:对于边界值测试,看模块会不会出现问题;

模块功能测试:通过黑盒,对模块测试。
其他单元测试项:性能,代码规范


框架unittest介绍:三个步骤
找到测试类(testcase),加载测试方法(runtest),执行测试方法。

1、被测模块model.py // 定义一个类,提供接口,实现两数相加

'''
实现两个数的加减
'''
class Calculator():
    def __init__(self,a,b):
        self.a = int(a)
        self.b = int(b)
    '''加法'''
    def add(self):
       return self.a + self.b
    '''减法'''
    def sub(self):
        return self.a - self.b
    '''乘法'''
    def mul(self):
        return self.a * self.b
    '''除法'''
    def div(self):
        return self.a / self.b

2、准备测试环境,编写测试用例

import unittest
from module import Calculator
from HTMLTestRunner2 import HTMLTestRunner 
"""
1、我们添加了 setUp() 和 tearDown() 两个方法(其实是重写了TestCase的这两个方法),
这两个方法在每个测试方法执行前以及执行后执行一次,
setUp用来为测试准备环境,tearDown用来清理环境,已备之后的测试
2、@unittest.skip  跳过某个case不执行

"""
class ModuleTest(unittest.TestCase):  //测试用例

    def setUp(self):  # 初始化,给被测模块的类传入参数
        self.cal = Calculator(8,4)

    def tearDown(self):
        pass
     // 调用方法,执行断言判断
    def test_add(self):
        result = self.cal.add()
        self.assertEqual(result,12)

    def test_sub(self):
        result = self.cal.sub()
        self.assertEqual(result, 4)

    def test_mul(self):
        result = self.cal.mul()
        self.assertEqual(result, 32)

    def test_div(self):
        result = self.cal.div()
        self.assertEqual(result, 2)

#if __name__ == "__main__":
#     unittest.main() 


if __name__ == "__main__":  
    #完全可以使用“unittest.main()”替代(前提是:所有的测试模块均以test开头)
    suite = unittest.TestSuite()  #第二步,构造测试集,加载需要用到的测试用例
    suite.addTest(ModuleTest("test_add"))
    suite.addTest(ModuleTest("test_sub"))
    suite.addTest(ModuleTest("test_mul"))
    suite.addTest(ModuleTest("test_div"))
    #执行
    #runner = unittest.TextTestRunner()
    # runner.run(suite)
    with open('HTMLReport.html','w') as f:
       runner = HTMLTestRunner(stream=f, title='MathFunc Test Report',
                                description='generated by HTMLTestRunner.',
                                verbosity=2)
       runner.run(suite)  //第三步,调用执行

#若不保存测试输出结果,执行如下命令
#result = unittest.TextTestRunner(verbosity = 2).run(suite)

3、自动构成测试集
suite = unittest.makeSuite(测试用例名称,prefix = 'test') (加载test开头的文件)

import pytest
import unittest
from module import Calculator
from HTMLTestRunner2 import HTMLTestRunner

class ModuleTest(unittest.TestCase):

    def setUp(self): 
        self.cal = Calculator(8,4)

    def tearDown(self):
        pass

    def test_add(self):
        result = self.cal.add()
        self.assertEqual(result,12)

    def test_sub(self):
        result = self.cal.sub()
        self.assertEqual(result, 4)

    def test_mul(self):
        result = self.cal.mul()
        self.assertEqual(result, 32)

    def test_div(self):
        result = self.cal.div()
        self.assertEqual(result, 2)

#如果在上面继续添加测试用例,为提高效率可以可以自动添加到测试集,如果不想把某些测试用例加载到测试集,**就不要用test开头**

if __name__ == "__main__": 
    suite = unittest.makeSuite(ModuleTest,prefix='test')
    #suite.addTest(ModuleTest("get_number")) 同样可以结合这个addtest使用
    print(suite.counTestCase())   #打印加载测试用例个数。
    runner = unittest.TextTestRunner()
    runner.run(suite) 

测试用例的判断:也可以集成这些判断,进行扩展。
这里写图片描述
这里写图片描述

扩展 1、跳过某些接口,运行测试用例
————-重写测试用例后,添加测试用例时,如何跳过某些用例,并给出出原因。
1、@unittest.skip('reason') 用例前加上装饰器,表明直接跳过。

@unittest.skip('notest')
def test_add(self):
        result = self.cal.add()
        self.assertEqual(result,12)

扩展2、根据某些特定的条件跳过一些测试用例

  1. skipIf(conditon,reason) // conditon 条件为真的话,就跳过并给出原因 reason
  2. skipUnless(condition,reason) //conditon 条件为真,就不跳过。

在测试模块中可以给出测试版本,选择版本跳过(测试时用例是一样编写的,可以用版本号选择跳过):

class Calculator():
   version = 1  //版本一
    def __init__(self,a,b):
        self.a = int(a)
        self.b = int(b)

    '''加法'''
    def add(self):
       return self.a + self.b
    '''减法'''
    def sub(self):
        return self.a - self.b
    '''乘法'''
    def mul(self):
        return self.a * self.b
    '''除法'''
    def div(self):
        return self.a / self.b

测试用编写时,可以使用选择跳过装饰器

@unittest.skipIf(Calculator.version == 1 ,'no test')
def test_add(self):
        result = self.cal.add()
        self.assertEqual(result,12)

扩展 3、预期结果失败 @exoextdFailure(func)
————-测试结果和预期结果不符合,不计入失败统计,断言的时有些结果不符合预期会发生执行错误,这个是否可以忽略不计入统计值

@unittest.expextdFailure
def test_add(self):
        result = self.cal.add()
        self.assertEqual(result,13)  //显然这里不等于13

这里写图片描述

扩展 4、Mock模拟测试
单元测试基本测试流程图:
这里写图片描述
( 设计测试用例— > 去测试基本模块里面对象,函数 —> 用到测试资源—>网络资源,第三方模块支撑)

存在的问题:单元测试脚本可能依赖于服务器搭建,第三方模块,以及测试结果难以知道,难以重复测试bug

解决 unittest.mock 模块: Mock模块像测试对象提供一套和测试资源完全相同的接口和方法,不关心具体实现,只关心具体结果。第三方模块还没有完成时,可以用mock 去模拟第三方模块,给出接口值。
1、 mock.Mock : 构造器,可以模拟其他类,增加属性

from unittest import mock
testmock = mock.Mock()  //创建一个mock实例
print(testmock)
print(dir(testmock))

1、1 mock提供的基本对象:

['assert_any_call', 'assert_called', 'assert_called_once', 
'assert_called_once_with', 'assert_called_with', 'assert_has_calls',
 'assert_not_called', 'attach_mock', 'call_args', 'call_args_list', 
'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 
'side_effect']

2、创建mock类,构造其他属性。
这里写图片描述

from unittest import mock

attrs = ['connect','disconnect']  #增加两个属性
testmock = mock.Mock(name='TestMock',spec=attrs)  # 创建一个mock对象,对象名字,对象属性

#testmock.connect.return_value = 200  #增加属性返回值
testmock.disconnect.return_value = 200

testmock.connect.side_effect = [200,404,501]  #定义三个返回值,也可以定义一个返回函数,调用一次就返回一次。
for i in range(3):
    print(testmock.connect())

3、Mock断言语句
这里写图片描述

3、1 假设测试时用到的,第三方接口模块
第三方模块可能还没有完成,输入输出都不够完整,此时使用mock改写无需关心第三方

"""
用 mock 模拟一个类,定义一个云端客户端,有四个基本的方法。
"""
from unittest import mock

class CouldClient(object):
    def connect(self):
        pass

    def disconnect(self):
        pass

    def upload(self):
        pass

    def download(self):
        pass

3、2 测试用例编写

import unittest
from unittest import mock
from mock_class import CouldClient

class TestCould(unittest.TestCase):  
    def setUp(self):
        self.obj = mock.Mock(CouldClient)  #构造 mock 实例传入改写测试类
    def tearDown(self):
        self.obj = None

# 改写并赋予测试类输出值,断言输出是否正确。
    def test_connect(self):
        self.obj.connect.return_value = 200
        self.assertEqual(self.obj.connect(), 200)


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

猜你喜欢

转载自blog.csdn.net/qq_37884273/article/details/82466361