zoukankan      html  css  js  c++  java
  • Django单元测试

    单元测试

    ​ 单元测试是实际开发中很重要但也经常被忽视的部分,其主要原因是编写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`')
    
  • 相关阅读:
    Goroutine被动调度之一(18)
    实战分析一个运行起来会卡死的Go程序
    Go语言调度器之盗取goroutine(17)
    第三章 Goroutine调度策略(16)
    非main goroutine的退出及调度循环(15)
    Go语言调度器之调度main goroutine(14)
    PHP经典面试题之 Redis 内存满了怎么办?
    【PHP】让新人快速理解ThinkPHP6中的事务操作
    面试官:说说swoole+PHP实现自动取消订单,还原库存等操作
    最新整理的PHP高级面试题来啦!【附答案】
  • 原文地址:https://www.cnblogs.com/ZSMblog/p/11677236.html
Copyright © 2011-2022 走看看