【Django】单元测试TestCase、Client的用法

1.单元测试

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作,是测试最小独立的单元模块

如果有需要,可以给项目进行单元测试,主要目的有消灭低级错误、减少和快速定位BUG、提高代码质量

2.django单元测试

我们在创建好一个APP的时候,它会在自动在APP目录创建一个tests.py文件,这个就是拿来做单元测试的

apps/users/tests.py

from django.test import TestCase


class MyTestCase(TestCase):

    @classmethod
    def setUpClass(cls):
        print('setUpClass')

    @classmethod
    def tearDownClass(cls):
        print('tearDownClass')

    def setUp(self):
        print("setUp")

    def tearDown(self):
        print("tearDown")

    def test_2_func(self):
        print("test_2_func")

    def test_1_func(self):
        print("test_1_func")


终端命令,有多种执行方法

python3 manage.py test -t .  # 执行所有测试
python manage.py test meiduo_mall.apps.users  # 执行某个APP的所有test文件
python manage.py test meiduo_mall.apps.users.tests   # 执行某个APP的某个tests文件


执行结果

Creating test database for alias 'default'...
System check identified no issues (0 silenced).
setUpClass
setUp
test_1_func
tearDown
.setUp
test_2_func
tearDown
.tearDownClass

----------------------------------------------------------------------
Ran 2 tests in 0.004s

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


从执行过程打印的信息我们可以知道

(1).测试类要继承TestCase类
(2).执行前会自动创建一个mysql数据库,执行后自动销毁
(3).setUpClass和tearDownClass这两个静态方法分别会在测试所有用例执行前后各执行一次
(4).setUp和tearDown这两个方法会在每个测试用例前后都各执行一次
(5).setUp和tearDown、def setUpClass和tearDownClass成对出现
(6).用例方法必须以test开头,并非自身往下执行,而是按照方法名字符按照ASCII码排序,顺序是0-9、A-Z、a-z
(7).测试用例执行成功返回一个小数点,失败则返回F

另外,在执行过程可能会遇到django.db.utils.OperationalError: (1366, "Incorrect string value: '\\xE7\\x94\\xA8\\xE6\\x88\\xB7' for column 'name' at row 5") 的问题

这个时候,打开Django的配置文件,在DATABASES配置项里添加一个TEST指定单元测试的字符编码

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # 数据库引擎
        ...
        "TEST":{
            "CHARSET":"utf8",
            "COLLATION":"utf8_general_ci"
        },
    },
}

根据以上信息,我们可以写一个登录、查询、登出的测试例子

from django.test import TestCase
from requests import Session


class MyTestCase(TestCase):
    session = None

    @classmethod
    def setUpClass(cls):
        info = {
            "username": "13978414080",
            "password": "123456789",
            "remembered": True
        }
        cls.session = Session()
        resp = cls.session.post("http://127.0.0.1:8000/login/", json=info)
        result = resp.json()
        if result["code"] == 0:
            print("登录成功")

    @classmethod
    def tearDownClass(cls):
        resp = cls.session.delete('http://127.0.0.1:8000/logout/')
        result = resp.json()
        if result["code"] == 0:
            print("已退出登录")

    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):
        resp = self.session.get("http://127.0.0.1:8000/addresses/")
        print(resp.json())

3.Client
3.1 Client与Session的区别

我们在上面的模拟测试中使用了requests.Session()来状态保持,其实也可以使用Client类,它还是与Session有些区别的
(1).Client不需要启动服务器就能测试Django项目,也只能在Django中测试
(2).Client的请求url不需要带协议和域名端口,只需要路径部分

3.2 GET和POST

(1)get (path,data={},follow=False,**extra)

(2)post (path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra)

content_type:默认是multipart/form-data,可以指定为application/json

这次我们使用Client实现注册、登录、查询、登出,登出之后再查询一下信息

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


class MyTestCase(TestCase):
    def setUp(self):
        print("setUp")

    def tearDown(self):
        print("tearDown")

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

    def do_register(self):
        _uuid = '0fdb75a8-d60e-4598-86bc-c3e7991aadf9'
        self.client.get("/image_codes/%s/" % _uuid)

        conn = get_redis_connection('verify_code')
        ret = conn.get("img_%s" % _uuid)
        mobile = "13977778888"

        self.client.get("/sms_codes/%s/?image_code=%s&image_code_id=%s" % (mobile,ret.decode(),_uuid))

        user_info = {
            "username": "13978414088",
            "password": "123456789",
            "password2": "123456789",
            "allow": True,
            "mobile": mobile,
            "sms_code": "123456",
        }
        resp = self.client.post('/register/', data=user_info, content_type='application/json')
        print(resp.json())

    def do_login(self):
        user_info = {
            "username": "13978414088",
            "password": "123456789",
            "remembered": True,
        }
        resp = self.client.post('/login/', data=user_info, content_type='application/json')
        print(resp.json())
    
    def do_info(self):
        resp = self.client.get('/info/')
        print(resp.json())

    def do_logout(self):
        self.client.delete('/logout/')
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

冰冷的希望

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

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

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

打赏作者

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

抵扣说明:

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

余额充值