Django单元测试

Stella981
• 阅读 321

单元测试

​ 单元测试是实际开发中很重要但也经常被忽视的部分,其主要原因是编写Web功能测试所耗费的时间可能会大于你开发此功能的时间,因此,对于需要快速开发、上线的业务来说,项目中关于单元测试的部分很少。但是对于需要长期维护的项目,还需要考虑增加单元测试。只是第一次编写时会比较耗费时间,一旦基础结构完成,后续跟着功能的增加来增加单元测试并不会耗费多少时间,但是收益却是十分明显的。

​ 单元测试的主要目的是让代码更健壮,尤其是在进行重构或者业务增加的时候,跑通单元测试,就意味着新加入的代码或者修改的代码没有问题。在实际开发中,单元测试的覆盖率没有那么高,其主要原因也是写单元测试的成本过高,尤其是对于很复杂的业务。下面就Django内置的测试工具进行说明。

TestCase中几个方法的说明

​ 在Django中运行测试用例时,如果我们使用的SQLite数据库,Django会帮助我们创建一个基于内存测试的数据库,用于测试。

​ 但是对于MySQL数据库,Django会直接用配置的数据库用户和密码创建一个名为test_student_db的数据库,用于测试。因此需要保证有建表和建库的权限

​ 当然,也可以自定义测试用的数据库名称,通过setting配置:

DATABASE = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mydatabaseuser',
        'NAME': 'mydatabase',
        'TEST': {
            'NAME': 'mytestdatabase', # 这里配置
        },
    },
}

Django提供了一个名为TestCase的基类,我们可以通过继承这个类来实现自己的测试逻辑。TestCase为我们系统了以下方法(需要用到的):

  • def setUp(self):用来初始化环境,包括创建初始化的数据,或者做一些其他准备工作。
  • def test_xxxx(self):方法后面的xxxx可以是任意东西。以test_开头的方法,会被认为是需要测试的方法,跑测试时会被执行,每个需要被测试的方法是相互独立的。
  • def tearDown(self):跟setUp相对,用来清理测试环境和测试数据。

样例代码:

Model层测试

主要保证数据的写入和查询是可用的,同时也需要保证我们在model所提供的方法是复合预期的。

比如在Model中增加了sex_show这样的属性,用来展示sex这个字段的中文显示,而不是1,2。当然,这个功能是Django已经提供给我们的。

from django.db import models

# Create your models here.

class Student(models.Model):
    SEX_ITEMS = [
        (1, '男'),
        (2, '女'),
        (0, '未知'),
    ]
    STATUS_ITEMS = [
        (0, '申请'),
        (1, '通过'),
        (2, '拒绝'),
    ]
    name = models.CharField(max_length=128, verbose_name='姓名')
    sex = models.IntegerField(choices=SEX_ITEMS, verbose_name='性别')
    profession = models.CharField(max_length=128, verbose_name='职业')
    email = models.EmailField(verbose_name='Email')
    qq = models.CharField(max_length=128, verbose_name='QQ')
    phone = models.CharField(max_length=128, verbose_name='电话')

    status = models.IntegerField(choices=STATUS_ITEMS, default=0, verbose_name='审核状态')
    created_time = models.DateTimeField(auto_now_add=True, editable=False, verbose_name='创建时间')

    def __str__(self):
        return '<Student: ()>'.format(self.name)

    class Meta:
        verbose_name = verbose_name_plural = '学员信息'

    @property
    def sex_show(self):
        return dict(self.SEX_ITEMS)[self.sex]

    @classmethod
    def get_all(cls):
        return cls.objects.all()

views.py同级目录下的test.py,它是App初始化时Django默认帮我们创建的

from django.test import TestCase, Client
from .models import Student

# Create your tests here.
class StudentTestCase(TestCase):
    def setUp(self) -> None:
        Student.objects.create(
            name='test',
            sex=1,
            email='test@test.com',
            profession='test职业',
            qq='123',
            phone='123456',
        )

    def test_create_and_sex_show(self):
        student = Student.objects.create(
            name='zhangsan',
            sex=1,
            email='zhangsan@test.com',
            profession='程序员',
            qq='123123',
            phone='12121212',
        )
        self.assertEqual(student.sex_show, '男', '性别字段内容更展示不一致')

    def test_filter(self):
        Student.objects.create(
            name='lisi',
            sex=1,
            email='lisi@test.com',
            profession='程序员',
            qq='2124325',
            phone='11111111'
        )
        name='test'
        students= Student.objects.filter(name=name)
        self.assertEqual(students.count(), 1, '应该只存在一个名称为{}的记录'.format(name))
        

在setUp中,创建了一条数据用于测试。test_create_and_sex_show用来测试数据创建以及sex字段的正确展示,test_filter测试查询是否可用。

需要说明的是,每一个以test_开头的函数都是独立运行的。因此,setUp和tearDown也会在每个函数运行时被执行。简单理解就是每个函数都处于独立的运行环境。

View层测试

test.py 添加如下代码

    def test_get_index(self):
        # 测试首页的可用性
        client = Client()
        response = client.get('/')
        self.assertEqual(response.status_code, 200, 'status code must be 200!')

    def test_post_student(self):
        client = Client()
        data = dict(
            name='test_for_post',
            sex=1,
            email='333@test.com',
            profession='程序员',
            qq='333',
            phone='222',
        )
        response=client.post('/', data)
        self.assertEqual(response.status_code, 302, 'status code must be 302!')

        response = client.get('/')
        self.assertEqual(b'test_for_post' in response.content, 'response content must contain `test_for_post`')
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Karen110 Karen110
2年前
​一篇文章总结一下Python库中关于时间的常见操作
前言本次来总结一下关于Python时间的相关操作,有一个有趣的问题。如果你的业务用不到时间相关的操作,你的业务基本上会一直用不到。但是如果你的业务一旦用到了时间操作,你就会发现,淦,到处都是时间操作。。。所以思来想去,还是总结一下吧,本次会采用类型注解方式。time包importtime时间戳从1970年1月1日00:00:00标准时区诞生到现在
Wesley13 Wesley13
2年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
2年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这