单元测试&Client和Unittest

单元测试中Client的特征

  • 状态保存

  • 只能使用在django中

  • 不需要启动服务,使用的是临时的数据库

  • 发送post请求,只需要路径,例如:/login, 不需要url

    • 如果发送json格式,需要指定数据格式
  • 测试由于是走临时数据库(mysql),所以,注册、登陆是一起的

断言

  • 我们在写代码测试接口或者函数的时候,我们对这个接口或者函数的返回值是有预期的,如果实际的返回值和我们预期的结果不一致,就说明这个接口或者函数是有 bug 的,也就是测试不通过。
  • 断言可以简单理解为:对预期和实际的结果进行比对,比对的结果是真或假,真表示成功,假表示失败。一般情况下,如果是失败的,还应该给出失败的原因。
  • Django 中的测试用例,是通过判断执行过程中有没有抛出异常来表示成功还是失败,抛出异常就表示失败。
  • Django 当中提供了多种断言方法,这些方法帮助我们进行断言,msg 参数是可选的描述信息,当断言方法失败时会抛出 AssertionError。
    在这里插入图片描述
 # 断言:预期结果和实际结果是否符合
 # 如果ret['code']和0相等,说明符合预期,测试通过,断言成功,msg的信息不会显示
 # 如果ret['code']和0不相等,说明不符合预期,测试失败,断言失败,msg的信息会显示
 # 断言失败,标志为F,抛出异常
      self.assertEqual(ret['code'], 0, msg=ret['errmsg'])


 # arg1和arg2相等,测试通过,标志为 .
 # arg1和arg2不相等,测试不通过,标志为 F,抛出异常,显示msg的信息
       unittest.assertEqual(arg1, arg2, msg=None)

测试中的unittest框架

  • 测试框架,不仅仅用于单元测试
  • python自动的测试包
  • 用法和django.test.TestCase类似

介绍

在这里插入图片描述

unittest核心要素的使用
"""
1. 测试用例
2. 容器,容器添加测试用例
3. 运行容器中的测试用例
"""
import unittest

# 测试类,继承于unittest.TestCase
class MyTest(unittest.TestCase):
    def test_1(self):
        print('test_1')

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

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

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

defaultTestLoader使用

"""
1. 测试用例
2. 容器,容器添加测试用例
3. 运行容器中的测试用例
"""
import unittest

# 测试类,继承于unittest.TestCase
class MyTest(unittest.TestCase):
    def test_1(self):
        print('test_11111111111111')

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

if __name__ == '__main__':
    # 2. 容器,容器添加测试用例
    # 默认找指定路径下,所有test开头的文件
    # 参数1:路径,参数2:指定的文件
    suite = unittest.defaultTestLoader.discover('./', 'test_2_demo.py')

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

unittest基本使用

"""
1. 导入unittest模块
2. 新建类,继承于unittest.TestCase
3. 类中方法
 3.1. 前、后置(不是必须的,有前置必须写后置,匹配的)
 3.2. test开头的测试用例(测试用例中有断言)
4. unittest.main()运行测试
5. 测试用例运行顺序:0~9, A~Z,  a~z
"""
import unittest

class MyTest(unittest.TestCase):
 @classmethod
 def setUpClass(cls) -> None:
     print('setUpClass')

 @classmethod
 def tearDownClass(cls) -> None:
     print('tearDownClass')

 def setUp(self) -> None:
     print('setUp')

 def tearDown(self) -> None:
     print('tearDown')

 def test_1(self):
     print('test_1111111')

 def test_s(self):
     print('test_s')
     a = 1 + 1
     self.assertEqual(a, 2, '结果不为2')

 def test_f(self):
     print('test_f')
     a = 1 + 2
     self.assertEqual(a, 3, '结果不为3')

 def xxx_xxx(self): # 不会执行非test开头的方法
     print('xxxxx')

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

参数化

import unittest
from parameterized import parameterized # 需要先安装模块

class MyTest(unittest.TestCase):
    def setUp(self) -> None:
        print('setUp')

    def tearDown(self) -> None:
        print('tearDown')
    
    # 1. 参数化参数:列表套元组
    # 2. 列表有几个元素,测试用来执行几次
    # 3. 元组元素的位置匹配测试用例的形参
    @parameterized.expand([('mike', '123'), ('yoyo', 'abc')])
    def test_params(self, name, pwd):
        print('name = %s, pwd = %s'%(name, pwd))


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

mock

在这里插入图片描述

Mock 类基本使用

# return_value的使用
import unittest
import unittest.mock

class MyTest(unittest.TestCase):
    def test_return(self):
        # 1. 创建Mock()对象,给return_value关键字传参
        mock_obj = unittest.mock.Mock(return_value=250)
        # mock_obj是对象,可调用对象,用法和函数一样
        ret = mock_obj()
        print(ret)
# side_effect的使用
import unittest
import unittest.mock

class MyTest(unittest.TestCase):
   def test_except(self):
       # 1. 创建Mock()对象,传递异常对象
       mock_obj = unittest.mock.Mock(side_effect=BaseException('自定义异常'))
       # mock_obj是对象,可调用对象,用法和函数一样
       mock_obj()

   def test_list(self):
       # 1. 创建Mock()对象,传递list
       mock_obj = unittest.mock.Mock(side_effect=[1,2,3])
       # mock_obj是对象,可调用对象,用法和函数一样
       print(mock_obj())
       print(mock_obj())
       print(mock_obj())
       print(mock_obj()) # err, StopIteration

   def test_func(self):
       def func(a, b):
           return a+b

       # 1. 创建Mock()对象,传递函数名
       mock_obj = unittest.mock.Mock(side_effect=func)
       # mock_obj是对象,可调用对象,用法和函数一样
       print(mock_obj(1, 1))
       # TypeError: func() missing 2 required positional arguments: 'a' and 'b'
       mock_obj()
# 通过mock.path或者patch 上下文管理器,限制mock范围
# patch 上下文管理器注意作用域问题
import unittest
import unittest.mock
import pay
import pay_status


class MyTest(unittest.TestCase):
   @unittest.mock.patch('pay.pay_way')
   def test_1(self, mock_obj):
       mock_obj.return_value = {"result": "success", "reason":"null"}

       ret = pay_status.pay_way_status()
       print("test_1 = ", ret)
       self.assertEqual(ret, '支付成功', '支付失败')

   def test_3(self):
       with unittest.mock.patch('pay.pay_way') as mock_obj:
           mock_obj.return_value = {"result": "success", "reason":"null"}

           ret = pay_status.pay_way_status()
           print("test_3 = ", ret)
           self.assertEqual(ret, '支付成功', '支付失败')


   def test_2(self):
       ret = pay_status.pay_way_status()
       print("test_2 = ", ret)
       self.assertEqual(ret, '支付成功', '支付失败')

if __name__ == '__main__':
   unittest.main()
# 类方法替换
from unittest import mock
import unittest

class Pay(object):
    def pay_way(self):
        """假设这里是一个支付的功能,未开发完
        支付成功返回:{"result": "success", "reason":"null"}
        支付失败返回:{"result": "fail", "reason":"余额不足"}
        reason返回失败原因
        """
        raise NotImplementedError('代码还没有实现')

    def pay_way_status(self):
        """根据支付的结果success或fail,判断跳转到对应页面
        假设这里的功能已经开发完成"""

        # todo 此时pay_way()函数并未完成!你先假定他完成了
        result = self.pay_way()
        print(result)

        if result["result"] == "success":
            return "支付成功"
        if result["result"] == "fail":
            return "支付失败"

class TestPayStatues(unittest.TestCase):
    '''单元测试用例'''
    def test_1(self):
        p = Pay()
        p.pay_way = unittest.mock.Mock(return_value={"result": "success", "reason":"null"})

        ret = p.pay_way_status()
        self.assertEqual(ret, '支付成功', '测试失败')

    @unittest.mock.patch.object(Pay, 'pay_way')
    def test_2(self, mock_obj):
        mock_obj.return_value={"result": "success", "reason":"null"}

        p = Pay()
        ret = p.pay_way_status()
        self.assertEqual(ret, '支付成功', '测试失败')

    def test_3(self):
        with unittest.mock.patch.object(Pay, 'pay_way') as mock_obj:
            mock_obj.return_value={"result": "success", "reason":"null"}
    
            p = Pay()
            ret = p.pay_way_status()
            self.assertEqual(ret, '支付成功', '测试失败')
常用的方法和属性
import unittest
import unittest.mock


class MockTest(unittest.TestCase):
 def test_return_value(self):
     mock_obj = unittest.mock.Mock(return_value=1999)
     result = mock_obj()
     print(result)  # 打印 1999

     mock_obj()
     print(mock_obj.called)  # 是否被调用过, 返回布尔值
     print(mock_obj.call_count)  # 获取调用测试, 返回调用测试
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值