django的单元测试框架unittest、覆盖率
django的单元测试
指定测试范围:
- 指定运行某些测试文件./manage.py test --pattern="tests_*.py" -v 2
- 运行所有测试文件./manage.py test -v 2
# Run all the tests in the animals.tests module
$ ./manage.py test animals.tests# Run all the tests found within the 'animals' package
$ ./manage.py test animals# Run just one test case
$ ./manage.py test animals.tests.AnimalTestCase# Run just one test method
$ ./manage.py test animals.tests.AnimalTestCase.test_animals_can_speak
提高测试速度
Running tests in parallel
As long as your tests are properly isolated, you can run them in parallel to gain a speed up on multi-core hardware. See test --parallel
.
临时数据库:
运行时会临时创建数据库,运行结束后删除,数据库名字:test_用到的数据库。猜测是使用migragtion文件创建的。
使用选项--keepdb可以保留测试数据库
The test --keepdb
option preserves the test database between test runs. It skips the create and destroy actions which can greatly decrease the time to run tests.
举例:
#!/usr/bin/env python
# -*- coding: utf- -*-
"""
@Author :
@Date : -- :
@Description : 本文件的作用描述
@File : test_demo.py
""" from unittest.mock import patch
from django.test import TestCase
import os def multiple(a, b):
return a * b class Calculator(object):
def add(self, a, b):
return a+b def is_error(self):
try:
os.mkdir("")
return False
except Exception as e:
return True def multiple(self, a, b):
return a * b # Mock一个函数。
class TestOneFunc(TestCase):
# 指定函数的写法:要先写当前文件名,即module name
@patch('test_demo.multiple')
def test_multiple(self, mock_multiple):
mock_multiple.return_value =
self.assertEqual(multiple(, ), ) class TestProducer(TestCase):
def setUp(self):
self.calculator = Calculator() # Mock的函数每次被调用返回不同的值
@patch.object(Calculator, 'add')
def test_effect(self, mock_add):
# 注意list的顺序要和后面的顺序一一对应
mock_add.side_effect = [, , ]
self.assertEqual(self.calculator.add(, ), )
self.assertEqual(self.calculator.add(, ), )
self.assertEqual(self.calculator.add(, ), ) # Mock一个对象里面的方法
@patch.object(Calculator, 'add')
def test_add1(self, mock_add1):
# 模拟add函数的返回值为3,所以不管真实结果是否是3,都没有影响
mock_add1.return_value =
self.assertEqual(self.calculator.add(, ), ) # 让Mock的函数抛出exception
@patch('os.mkdir')
def test_exception(self, mock_mkdir):
mock_mkdir.side_effect = Exception
self.assertEqual(self.calculator.is_error(), True) # Mock多个函数,主要是注意顺序
@patch.object(Calculator, 'add')
@patch.object(Calculator, 'multiple')
def test_both(self, mock_multiple, mock_add):
mock_add.return_value =
mock_multiple.return_value =
self.assertEqual(self.calculator.add(, ), )
self.assertEqual(self.calculator.multiple(, ), ) class ClassTemplate(object):
def __init__(self, name):
# __name c是私有变量,只有类本身可以访问,子类也不可以访问
# _name 是受保护变量,类本身和子类可以访问,from module import *无法导入
# decorator/迭代器/yield/
self.__name = name def run(self):
print("my name is %s" % self.__name) @staticmethod
def staticmethod(value):
print("my value is {}".format(value)) if __name__ == '__main__':
ClassTemplate('a_name').run()
ClassTemplate.staticmethod('a_value')
from unittest.mock import patch, Mock
from django.test import TestCase, Client, RequestFactory
import os
# import requests
import client def multiple(a, b):
return a * b class Calculator(object):
def add(self, a, b):
return a+b def is_error(self):
try:
os.mkdir("")
return False
except Exception as e:
return True def multiple(self, a, b):
return a * b # Mock一个函数。
class TestOneFunc(TestCase):
def setUp(self):
self.client = Client()
self.request_factory = RequestFactory()
# self.calculator = Calculator() # 指定函数的写法:要先写当前文件名,即module name
@patch('test_demo.multiple')
def test_multiple(self, mock_multiple):
# https://docs.djangoproject.com/zh-hans/2.1/topics/testing/advanced/
# 主要用于构造request对象,与client对比,没有发生url接口的调用。
request = self.request_factory.post('/vpc/list', data={'start': , 'length': }) # 主要用于模仿url请求,调用并返回请求结果。
response = self.client.get('/vpc/list') mock_multiple.return_value =
self.assertEqual(multiple(, ), ) class TestProducer(TestCase):
def setUp(self):
self.calculator = Calculator() # Mock的函数每次被调用返回不同的值
@patch.object(Calculator, 'add')
def test_effect(self, mock_add):
# 注意list的顺序要和后面的顺序一一对应
mock_add.side_effect = [, , ]
self.assertEqual(self.calculator.add(, ), )
self.assertEqual(self.calculator.add(, ), )
self.assertEqual(self.calculator.add(, ), ) # Mock一个对象里面的方法
@patch.object(Calculator, 'add')
def test_add1(self, mock_add1):
# 模拟add函数的返回值为3,所以不管真实结果是否是3,都没有影响
mock_add1.return_value =
self.assertEqual(self.calculator.add(, ), ) # 让Mock的函数抛出exception
@patch('os.mkdir')
def test_exception(self, mock_mkdir):
mock_mkdir.side_effect = Exception
self.assertEqual(self.calculator.is_error(), True) # Mock多个函数,主要是注意顺序
@patch.object(Calculator, 'add')
@patch.object(Calculator, 'multiple')
def test_both(self, mock_multiple, mock_add):
mock_add.return_value =
mock_multiple.return_value =
self.assertEqual(self.calculator.add(, ), )
self.assertEqual(self.calculator.multiple(, ), ) class TestClient(TestCase): def test_success_request(self):
success_send = Mock(return_value='')
client.send_request = success_send
self.assertEqual(client.visit_ustack(), '') def test_fail_request(self):
fail_send = Mock(return_value='')
client.send_request = fail_send
self.assertEqual(client.visit_ustack(), '') class TestClient1(TestCase): def test_call_send_request_with_right_arguments(self):
client.send_request = Mock()
client.visit_ustack()
# Mock对象的called属性表示该mock对象是否被调用过。
self.assertEqual(client.send_request.called, True)
# Mock对象的call_args表示该mock对象被调用的tuple,tuple的每个成员都是一个mock.call对象。
# mock.call这个对象代表了一次对mock对象的调用,其内容是一个tuple,含有两个元素,
# 第一个元素是调用mock对象时的位置参数(*args),第二个元素是调用mock对象时的关键字参数( ** kwargs)
call_args = client.send_request.call_args
self.assertIsInstance(call_args[][], str) # 使用patch或者patch.object的目的是为了控制mock的范围,意思就是在一个函数范围内,
# 或者一个类的范围内,或者with语句的范围内mock掉一个对象
class TestClient2(TestCase): def test_success_request(self):
status_code = ''
success_send = Mock(return_value=status_code)
with patch('client.send_request', success_send):
from client import visit_ustack
self.assertEqual(visit_ustack(), status_code) # patch用法
def test_fail_request(self):
status_code = ''
fail_send = Mock(return_value=status_code)
with patch('client.send_request', fail_send):
from client import visit_ustack
self.assertEqual(visit_ustack(), status_code) # patch.object用法
def test_fail_request2(self):
status_code = ''
fail_send = Mock(return_value=status_code)
with patch.object(client, 'send_request', fail_send):
from client import visit_ustack
self.assertEqual(visit_ustack(), status_code) class ClassTemplate(object):
def __init__(self, name):
# __name c是私有变量,只有类本身可以访问,子类也不可以访问
# _name 是受保护变量,类本身和子类可以访问,from module import *无法导入
# decorator/迭代器/yield/
self.__name = name @classmethod
def class_method(cls):
cls.staticmethod('test') def run(self):
print("my name is %s" % self.__name) @staticmethod
def staticmethod(value):
print("my value is {}".format(value)) if __name__ == '__main__':
ClassTemplate('a_name').run()
ClassTemplate.staticmethod('a_value')
ClassTemplate.class_method()
覆盖率
- 安装coverage包:
pip install coverage
- 执行用例
coverage run --source '.' manage.py test -v 2
- 查看覆盖率:
macbook:portal zhaoxueyong$ coverage report
Mock
Mock对象的一般用法是这样的:
找到你要替换的对象,这个对象可以是一个类,或者是一个函数,或者是一个类实例。
然后实例化Mock类得到一个mock对象,并且设置这个mock对象的行为,比如被调用的时候返回什么值,被访问成员的时候返回什么值等。
使用这个mock对象替换掉我们想替换的对象,也就是步骤1中确定的对象。
之后就可以开始写测试代码,这个时候我们可以保证我们替换掉的对象在测试用例执行的过程中行为和我们预设的一样。
- 可以替换自己写的模块的对象,其实也可以替换标准库和第三方模块的对象,方法是一样的:先import进来,然后替换掉指定的对象就可以了
Client vs RequestFactory
from django.test import TestCase, Client, RequestFactory
RequestFactory
and Client
have some very different use-cases. To put it in a single sentence: RequestFactory
returns a request
, while Client
returns a response
.
The RequestFactory
does what it says - it's a factory to create request
objects. Nothing more, nothing less.
The Client
is used to fake a complete request-response cycle. It will create a request
object, which it then passes through a WSGI handler. This handler resolves the url, calls the appropriate middleware, and runs the view. It then returns the response object. It has the added benefit that it gathers a lot of extra data on the response
object that is extremely useful for testing.
The RequestFactory
doesn't actually touch any of your code, but the request
object can be used to test parts of your code that require a valid request
. The Client
runs your views, so in order to test your views, you need to use the Client
and inspect the response. Be sure to check out the documentation on the Client
.
测试用例执行前后的工作:
class TestMathFunc(unittest.TestCase):
"""Test mathfuc.py"""
# 所有测试用例执行前执行一次
@classmethod
def setUpClass(cls):
print "This setUpClass() method only called once."
# 所有测试用例执行后执行一次
@classmethod
def tearDownClass(cls):
print "This tearDownClass() method only called once too."
# 每个用例前执行一次
def setUp(self):
print "do something before test.Prepare environment."
# 每个用例后执行一次
def tearDown(self):
print "do something after test.Clean up."
@unittest.skip("I don't want to run this case.")
def test_divide(self):
"""Test method divide(a, b)"""
print "divide"
self.assertEqual(2, divide(6, 3))
self.assertEqual(2.5, divide(5, 2))
测试套以及html输出报告:
import unittest
from test_mathfunc import TestMathFunc
from HTMLTestRunner import HTMLTestRunner if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc)) with open('HTMLReport.html', 'w') as f:
runner = HTMLTestRunner(stream=f,
title='MathFunc Test Report',
description='generated by HTMLTestRunner.',
verbosity=
)
runner.run(suite)
test --pattern="test_plugin_check.py" -v 3 --debug-mode --debug-sql --parallel 2
参考:
1、https://www.jianshu.com/p/b87d7b4a222a
2、https://segmentfault.com/a/1190000002965620
3、https://docs.python.org/3.7/library/unittest.mock.html
4、https://docs.djangoproject.com/zh-hans/2.1/topics/testing/overview/
5、https://docs.djangoproject.com/zh-hans/2.1/topics/testing/overview/
django的单元测试框架unittest、覆盖率的更多相关文章
- 单元测试框架unittest
单元测试:单元测试,是指对软件中的最小可测试单元进行检查和验证,对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义如:c语言中单元指一个函数,java里单元指一个类,图形化的软件中可以 ...
- Python单元测试框架unittest使用方法讲解
这篇文章主要介绍了Python单元测试框架unittest使用方法讲解,本文讲解了unittest概述.命令行接口.测试案例自动搜索.创建测试代码.构建测试套件方法等内容,需要的朋友可以参考下 概 ...
- Python单元测试框架unittest之深入学习
前言 前几篇文章该要地介绍了python单元测试框架unittest的使用,本篇文章系统介绍unittest框架. 一.unittest核心工作原理 unittest中最核心的四个概念是:test c ...
- Python单元测试框架unittest之单用例管理(一)
一.概述 本文介绍python的单元测试框架unittest,unittest原名为PyUnit,是由java的JUnit衍生而来,这是Python自带的标准模块unittest.unittest是基 ...
- python之使用单元测试框架unittest执行自动化测试
Python中有一个自带的单元测试框架是unittest模块,用它来做单元测试,它里面封装好了一些校验返回的结果方法和一些用例执行前的初始化操作. 单元测试框架即一堆工具的集合. 在说unittest ...
- Python单元测试框架unittest
学习接口自动化测试时接触了unittest单元测试框架,学习时参照了虫师编写的<selenium2自动化测试实战>,个人觉得里面讲的例子还比较容易理解的. 一.基础 1.main()和框架 ...
- Python必会的单元测试框架 —— unittest
用Python搭建自动化测试框架,我们需要组织用例以及测试执行,这里博主推荐Python的标准库——unittest. unittest是xUnit系列框架中的一员,如果你了解xUnit的其他成员,那 ...
- Appium+python的单元测试框架unittest(1)(转)
unittest为python语言自带的单元测试框架,python把unittest封装为一个标准模块封装在python开发包中.unittest中常用的类有:unittest.TestCase.un ...
- Appium+python的单元测试框架unittest(4)——断言(转)
(原文:https://www.cnblogs.com/fancy0158/p/10051576.html) 在我们编写的测试用例中,测试步骤和预期结果是必不可少的.当我们运行测试用例时,得到一个运行 ...
随机推荐
- redhat重置密码
当忘记虚拟机密码时怎么办? 1.启动虚拟机,当虚拟机显示输入enter启动时输入e 2.再次用上下键选中你平时启动linux的那一项(类似于kernel /boot/vmlinuz-2.4.18-14 ...
- Ubuntu16.04下HBase的安装与配置
一.环境 os : Ubuntu 16.04 LTS 64bit jdk : 1.8.0_161 hadoop : mysql : hive : hbase: -hadoop2 安装HBase前,系统 ...
- Ionic Js九:列表操作
列表是一个应用广泛在几乎所有移动app中的界面元素.ionList 和 ionItem 这两个指令还支持多种多样的交互模式,比如移除其中的某一项,拖动重新排序,滑动编辑等等. <ion-list ...
- 《Android源码设计模式》--原型模式
No1: 原型模式使用场景: 1)类初始化需要消耗非常多的资源,这个资源包括数据.硬件资源等,通过原型复制避免这些消耗 2)通过new产生一个对象需要非常繁琐的数据准备货访问权限,这是可以使用原型模式 ...
- 深度学习基础系列(十一)| Keras中图像增强技术详解
在深度学习中,数据短缺是我们经常面临的一个问题,虽然现在有不少公开数据集,但跟大公司掌握的海量数据集相比,数量上仍然偏少,而某些特定领域的数据采集更是非常困难.根据之前的学习可知,数据量少带来的最直接 ...
- JAVAEE——宜立方商城07:Linux上搭建Solr服务、数据库导入索引库、搜索功能的实现
1. 学习计划 1.Solr服务搭建 2.Solrj使用测试 3.把数据库中的数据导入索引库 4.搜索功能的实现 2. Solr服务搭建 2.1. Solr的环境 Solr是java开发. 需要安装j ...
- 哪种写法更好?<script></script> vs/or <script type=”text/javasript”></script>
一直很奇怪 哪种写法更好<script type=“text/javascript”>…</script> or <script>…</script>? ...
- Kolla O版本部署
Kolla O版部署和之前的版本还是有些区别的,环境还是all-in-one 基本准备: 关闭Selina和firewalld [root@kolla ~]# cat /etc/redhat-rele ...
- [ 转载 ] Java中常用的设计模式
Java中常用的设计模式 1.单例模式 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个 ...
- python opencv3 静态图片检测人脸
git:https://github.com/linyi0604/Computer-Vision # coding:utf-8 import cv2 filename = "../data/ ...