单元测试---TestCase,Client,断言

概述:

1: 作用: 对测类,方法,函数进行测试。
2: 单元测试是测试的最小单位
3: 由于django的特殊性,通过接口测试单元。因为django中的每个单元都是在类视图中。
4: 单元测试的好处:

消除低级错误
减少Bug, 消除低级Bug
提高代码质量(测试后快速优化)

一: 基于Django的单元测试:

1: 概述:

Django环境
1: 配置文件mysql设置字符集编码为utf-8
2: 数据库的用户最好是用root,因为测试过程中会出现自动建临时库的操作。

每个应用自带test.py
每个类必须继承django.test.TestCase
每个类可以具备一个前置和后置方法
测试方法的名称必须以test开头

2: 样例

from django.test import TestCase

# Create your tests here.


class MyClassTestCase(TestCase):
    def setUp(self):
        """前置准备"""
        print('setUp')

    def tearDown(self):
        """后置处理"""
        print('tearDown')

    def test_my_func(self):
        """测试功能"""
        print('测试用例')
    def test_my_func2(self):
        """测试功能"""
        print('测试用例2')

注意: django执行测试用例时,每次都会先执行setUp方法,最后必然执行tearDown方法。比如上面的就会执行两次setUp和两次tearDown。

3: 单元测试命令运行:

1: 执行所有的Test文件:

cd manager.py所在的目录
python manager.py test

2: 运行某个app下面的所有的测试用例:

cd manager.py所在的目录
python manager.py test meiduo_mall.apps.users

3: 运行某个指定的测试用例:(最常用)

cd manager.py所在的目录
python manager.py test meiduo_mall.apps.users.tests

4: 运行某个指定测试用例的某个类:

cd manager.py所在的目录
python manager.py test meiduo_mall.apps.users.tests.MyClassTestCase

5: 运行某个指定测试用例的某个类中的方法:

cd manager.py所在的目录
python manager.py test meiduo_mall.apps.users.tests.MyClassTestCase.test_my_func

二:TestCase类

1: Django的TestCase继承了Python的unittest.TestCase, 所以这两个功能大部分一致(Python很多框架都集成了unittest)。

django.test.TestCase类主要由前、后置处理方法 和test开头的方法组成
test开头的方法 是编写了测试逻辑的用例
setUp方法 (名字固定)在每一个测试方法执行之前被调用
tearDown方法(名字固定) 在每一个测试方法执行之前被调用
setUpClass类方法(名字固定)在整个类运行前执行只执行一次
tearDownClass类方法(名字固定)在调用整个类测试方法后执行一次

2: 样例

rom django.test import TestCase


class MyClassTestCase(TestCase):
    # 在所有测试用例执行之前调用
    @classmethod
    def setUpClass(cls):
        print('setUpClass在所有测试用例执行之前调用')

    # 在所有测试用例执行之后调用
    @classmethod
    def tearDownClass(cls):
        print('tearDownClass在所有测试用例执行之后调用')

    # 在每一个测试方法执行之前被调用
    def setUp(self):
        print('setUp在每一个测试方法执行之前被调用')

    # 在每一个测试方法执行之后被调用
    def tearDown(self):
        print('tearDown在每一个测试方法执行之前被调用')

    # 测试方法以 test 开头
    def test_1(self):
        print('test 1')

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

在这里插入图片描述
3:setUpClass 和 tearDownClass应用场景:

  • 当类中的测试用例需要共享一些数据,比如,我们测试:获取用户信息、获取用户浏览器记录、获取用户地址列表时,需要先进行用户登录,测试完成之后进行用户退出。

  • 如果我们通过 setUp 和 teardown 方法,那么我们就需要多次进行登录、退出,这样是重复的代码,通常是不必要的。

  • 我们可以通过 setUpClass 和 tearDownClass 做类级别的前置处理(例如,用户登录)和后置处理(例如,退出登录),这两个方法每个类中只会执行一次。

# 定义 setUpClass: 用户登录
# 定义 tearDownClass: 用户退出
# 定义测试方法:获取用户信息、获取用户浏览器记录、获取用户地址列表

from django.test import TestCase
from requests import Session


class MyClassTestCase(TestCase):
    # 类属性
    session = None

    # 在所有测试用例执行之前调用
    @classmethod
    def setUpClass(cls):
        print('setUpClass')
        # 构造账号密码
        info = {
            "username": "mike123",
            "password": "chuanzhi12345",
            "remembered": True
        }

        # 实例化session对象,此为类属性
        cls.session = Session()

        # 登录
        resp = cls.session.post(
            'http://127.0.0.1:8000/login/',
            json=info
        )

        # 获取 json 响应
        result = resp.json()

        # 检查是否登录成功
        # 检查是否登录成功
        if result['code'] != 0:
            print('登录失败')

    # 在所有测试用例执行之后调用
    @classmethod
    def tearDownClass(cls):
        print('tearDownClass')
        # 登出
        cls.session.delete('http://127.0.0.1:8000/logout/')

    # 获取登陆用户
    def test_1_info(self):
        # 查看用户状态
        resp = self.session.get('http://127.0.0.1:8000/info/')
        print(resp.json())

    # 获取用户浏览历史
    def test_2_history(self):
        resp = self.session.get('http://127.0.0.1:8000/browse_histories/')
        print(resp.json())

    def test_3_addresses(self):
        # 调用查看地址列表接口
        url = 'http://127.0.0.1:8000/addresses/'
        resp = self.session.get(url)
        print(resp.json())
$ python manage.py test meiduo_mall.apps.users.test_code.test_2_case
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
setUpClass
{'code': 0, 'errmsg': 'ok', 'info_data': {'username': 'mike123', 'mobile': '13344445555', 'email': '', 'email_active': False}}
.{'code': 0, 'errmsg': 'ok', 'skus': []}
.{'code': 0, 'errmsg': 'ok', 'default_address_id': None, 'addresses': []}
.tearDownClass

----------------------------------------------------------------------
Ran 3 tests in 0.383s

OK
Destroying test database for alias 'default'...

三: Client类:

1: Client的特点:

  • Client的实例对象可以进行状态保持
  • 使用Client进行测试时,不需要启动服务器
  • Client测试时Django特有的,只能测试Dijango代码
  • Client的get, post方法不需要携带协议,域名,端口,只需要携带路径
  • 如果发送的是json数据,需要指定数据格式content_type='application/json’

2:案例: 对美多商城进行注册,然后登录,然后查看用户信息,最后退出登录。


from django.test import TestCase
import requests
from django_redis import get_redis_connection

class MyTest(TestCase):

    def setUp(self):
        print("setUp")
        # 创建一个Session实例对象
        self.s = requests.Session()

    def tearDown(self):
        print("tearDown")
        del self.s

    def test_xxx(self):
        # self.do_register()
        self.do_login()
        self.do_info()
        self.do_logout()


    # 注册
    def do_register(self):
        print("进行注册")
        _uuid = "0fdb75a8-d60e-4598-86bc-c3e7991aadf9"
        # 发送获取图片验证码请求
        self.s.get("http://localhost:8000/image_codes/%s/" % _uuid)
        # redis中获取图片验证码
        conn = get_redis_connection("verify_code")
        image_code_from_redis = conn.get("img_%s" % _uuid).decode()
        print(image_code_from_redis)

        # 发送短信验证码
        mobile = "13377778888"
        r = self.s.get('http://localhost:8000/sms_codes/%s/?image_code=%s&image_code_id=%s' % (mobile, image_code_from_redis, _uuid))
        print('短信验证码结果 = ', r.json())

        # 进行注册
        info = {
            "username": "mikeabc",
            "password": "chuanzhi12345",
            "password2": "chuanzhi12345",
            "allow": True,
            "mobile": mobile,
            "sms_code": "123456"
        }

        r = self.s.post('http://localhost:8000/register/', json=info)
        print('注册结果 = ', r.json())

    # 登陆
    def do_login(self):
        info = {
            "username": "mikeabc",
            "password": "chuanzhi12345",
            "remembered": True,
        }

        r = self.s.post('http://localhost:8000/login/', json=info)
        print('登陆结果 = ', r.json())

    # 获取用户信息
    def do_info(self):
        r = self.s.get('http://localhost:8000/info/')
        print('用户信息结果 = ', r.json())

    # 退出登陆
    def do_logout(self):
        r = self.s.delete('http://localhost:8000/logout/')
        print('登出结果 = ', r.json())

将上面代码转换成使用Client类来操作:

from django.test import TestCase, Client
import requests
from django_redis import get_redis_connection


class MyTest(TestCase):
    def setUp(self) -> None:
        print('setUp')
        # 创建一个Client()对象,实例属性
        self.s = Client()


    def tearDown(self) -> None:
        print('tearDown')
        del self.s # 删除变量,不是必须,这里只是为了匹配

    def test_xxx(self):
        self.do_register()
        self.do_login()
        self.do_info()
        self.do_logout()
        self.do_info()

    def do_register(self):
        """注册"""
        print('注册')
        _uuid = '0fdb75a8-d60e-4598-86bc-c3e7991aadf9'

        # a.发送图片验证玛
        # http://域名或ip:端口/image_codes/0fdb75a8-d60e-4598-86bc-c3e7991aadf9/
        self.s.get('/image_codes/%s/' % _uuid)


        # b.发送短信验证码,需要上一步图片验证码(直接读redis)
        # 从redis读取图片验证码
        # 1.2 读取redis中的图形验证码
        conn = get_redis_connection('verify_code')
        # redis返回的数据,如果没有则None,如果有返回的是字符串的字节形式b'CFGR' --> b'CFGR'.decode() --> 'CFGR'
        image_code_from_redis = conn.get('img_%s' % _uuid)
        image_code = image_code_from_redis.decode()
        print(image_code)

        mobile = "13377778888"
        # http://域名或ip:端口/sms_codes/任意手机号/?image_code=上一步获取的验证码&image_code_id=0fdb75a8-d60e-4598-86bc-c3e7991aadf9
        r = self.s.get('/sms_codes/%s/?image_code=%s&image_code_id=%s' % (mobile, image_code, _uuid))
        print('短信验证码结果 = ', r.json())

        # c.注册(手机验证为上一步,验证码固定为123456)
        info = {
            "username":"mikemike",
            "password":"chuanzhi12345",
            "password2":"chuanzhi12345",
            "allow":True,
            "mobile":mobile,
            "sms_code":"123456"
        }

        # client.post只有data关键字参数,需要通过content_type='application/json'指定请求体为json格式
        r = self.s.post('/register/', data=info, content_type='application/json')
        print('注册结果 = ', r.json())

    def do_login(self):
        info = {
            "username":"mikemike",
            "password":"chuanzhi12345",
            "remembered":True,
        }

        r = self.s.post('/login/', data=info, content_type='application/json')
        print('登陆结果 = ', r.json())

    def do_info(self):
        r = self.s.get('/info/')
        print('用户信息结果 = ', r.json())

    def do_logout(self):
        r = self.s.delete('/logout/')
        print('登出结果 = ', r.json())

测试结果:
在这里插入图片描述

四:断言

  • Django 当中提供了多种断言方法,这些方法帮助我们进行断言,msg 参数是可选的描述信息,当断言方法失败时会抛出 AssertionError。

常见断言方法如下:
在这里插入图片描述

        # 断言:预期结果和实际结果是否符合
        # 如果ret['code']和0相等,说明符合预期,测试通过,断言成功,msg的信息不会显示
        # 如果ret['code']和0不相等,说明不符合预期,测试失败,断言失败,msg的信息会显示
        # 断言失败,标志为F,抛出异常
        self.assertEqual(ret['code'], 0, msg=ret['errmsg'])
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

奈何碎银没有几两

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

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

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

打赏作者

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

抵扣说明:

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

余额充值