[Django] 单元测试小记
2016-07-18 19:30
489 查看
从前很少写单元测试了,特别是web应用。最近不知不觉喜欢起来这个事情了,发现单元测试对于软件的模块,正交性有很大促进作用,因为函数,模块写的不合理,单元测试写起来就麻烦的多呀。公司的项目一直都是用Django,所以写点django单元测试的小总结,记录为主,备查。
测试的场景
框架Django1.8 测试工具 unittest, 要记得给test设置一个独特的settings。测试请求 也就是测试整个view部分 官方案例 其中可能会遇到登录,或者时session怎么模拟的问题
测试带有orm的模块
需要mock的测试,比较多的情况是有第三方API调用, 发邮件,发短信这种
unittest提供的断言种类挺多,但是经常用的也就几个
self.assertContains,
self.assertEqual,
self.assertTrue
顺便提下有用的选项(我这里是单独给测试写了一个settings), 为了提高测试速度,可以把用不到的中间件,installed_apps之类的多余配置给去掉。
测试全部用例 python manage.py test --setting settings_test 测试某个APP python manage.py test appname --setting settings_test 测试某个app下的TeseCase类 python manage.py test alarm.tests.ModelTestCase --setting settings_test -v {1,2,3} 数字越大,显示的输出越详细,测试的日志信息 python manage.py test --setting settings_test -v3 其他的选项请查看 --help python manage.py test --help
用请求测试 views函数
DJANGO中提供了Client类来模拟http请求,可以模拟不同的method,然后就是请求参数的模拟,用起来很方面。#coding:utf-8 from django.test import TestCase, Client from sendviews import * from core.tests import create_user class SendviewsTestCase(TestCase): def setUp(self): self.user = create_user() self.device = Device(hostname="CN-BJ-0000-00", mac="ff:ff:ff:ff:ff:ff", user=self.user).save() def test_creat_sms(self): c = Client() rep = c.post("/acquireportal/createsms",{"phone": "13988902345", "ssid": "erya", "dmac": "ff:ff:ff:ff:ff:ff"}) # 测试http请求的返回码是否正确 self.assertEqual(rep.status_code, 200) # 测试response的内容是否包含字符串 self.assertContains(rep, "OK") # 测试response的内容是否包含字符串 方法二 self.assertTrue('OK' in rep.content)
HTML 文本测试,使用 constants 来判断并不是个好的选择,可以用render之后的字符串对比。
对于需要登陆的view,有client也比较容易操作,还有一些特殊的session的检测等, 我这里做了一个简单的封装
from django.test import Client def init_client(user): client = Client() client.login(username=user.username, password="lzz") s = client.session s['cur_user_id'] = user.id s.save() return client
带有mock的测试
对模块中的方法mock或者是对一个对象中的方法进行mock。真对测试函数中一些无法直接测试的函数设置默认的返回值, py3标准库中已经有了mock模块,py2需要自己安装, 推荐教程 使用Pyhton Mock进行单元测试1。 下面是个实际的代码片段。import mock from django.test import TestCase from core.models import Tenant from alarm.models import * from .controler import TenantAlarm class ModelTestCase(TestCase): def setUp(self): self.tenant = Tenant.objects.create(domainname="erya", comname=u"尔雅") @mock.patch.object(TenantAlarm, "sendAlarm") def test_record_alarm(self, mock_method): # record_alarm 这个中会调用sendAlarm方法 mock_method.return_value = None content = "ccccc" atype = 0 rec_uid = 0 Alarm().record_alarm(content=content, atype=0, rec_tid=self.tenant.id) class TenantAlarmTestCase(TestCase): def setUp(self): self.tenant = Tenant.objects.create(domainname="erya", comname=u"尔雅") @mock.patch.object(TenantAlarm, "sendSMS", return_value=None) @mock.patch.object(TenantAlarm, "sendEmail", return_value=None) def test_send_alarm(self, method1, method2): content = u"报警了" ta = TenantAlarm(self.tenant.id, content, {u'SMS': 0, u'EMAIL': 0}) ta.sendAlarm() @mock.patch('util.sendsms_com.send', return_value=1) def test_sendsms(self, send): ta = TenantAlarm(self.tenant.id, self.content, {u'SMS': 0, u'EMAIL': 0}) ta.sendSMS() self.assertEqual(0, Account.objects.get(tenant=self.tenant).sms_num) self.account.sms_num = 100 self.account.save() ta.sendSMS() self.assertEqual(99, Account.objects.get(tenant=self.tenant).sms_num)
coverage
coverage是一个检查单元测试覆盖率的工具,django的文档中也有简要的说明coverage的集成 文档地址#测试并收集测试信息 coverage run --source='.' manage.py test --setting mandela.settings_test #查看测试结果 coverage report -m Name Stmts Miss Cover Missing ---------------------------------------------------------------------------------------- acquireportal/__init__.py 0 0 100% acquireportal/controler.py 65 47 28% 22-56, 60-71, 76-79 acquireportal/migrations/0001_initial.py 6 0 100% acquireportal/migrations/0002_auto_20160622_1059.py 6 0 100% acquireportal/migrations/0003_auto_20160622_1100.py 5 0 100% .... ---------------------------------------------------------------------------------------- TOTAL 8013 5858 27%
覆盖率挺低的
相关文章推荐
- Google浏览器跨域
- django(三)
- Django 1.6.5模板搭建
- #include<algorithm>中的sort算法
- 项目中坑记录:mongo 插入失败无提示
- GoldenGate单向复制配置(支持DDL复制)
- Django URL传递参数的方法总结(转)
- Google Play 开发者注意事项
- Django会话、用户和注册
- Proximal Algorithms
- Calendar日历类和GregorianCalendar公历类用法的一个小结
- Mongoose学习参考文档——基础篇
- go 获得当天0时0分0秒时间戳
- golang的 Web 开发,提示找不到模板文件
- Google protobuf
- Django 模板目录配置
- 如何使360浏览器中的Google可用
- Django过滤器列表
- Google APAC 2017 University Test Round A
- Why Django paginator take long time to page?