在django下很容易写测试,只需要继承DjangoTestCase,它会自动创建一个测试数据库,每次运行时加载必要的fixture数据,以保证每个测试的初始状态是一致、可预测的。其前提是必须使用它的dbmodel,如果使用MySQL, Oracle等关系型数据库,这自然不是个问题。如果使用其它数据库,例如当前相当流行的NoSQL,这时DjangoTestCase就不能直接拿来用了。如果我们hack一下django,也是可以使用DjangoTestCase的。以mongodb为例,我使用的是django1.2,1.2以下的版本不能用这里的方式,我没有研究过,但我相信也是能hack的。
django有TestRunner,用来启动测试,加载fixture的工作就是在这里做的。默认的TestRunner是'django.test.simple.DjangoTestSuiteRunner',而它加载fixture的实际上调用的是loaddata命令。所以要实现fixture的加载工作,最简单的方式就是重新定义loaddata命令,让它将数据加载到mongodb中。随便选择一个app,在它的下面创建management目录,再在management下创建commands目录,然后再在其下创建loaddata.py,每个目录下面也都需要创建__init__.py文件。创建命令的工作可以参考
这里。一般fixture的格式是用json格式,也可以用xml,写起来就会麻烦些,也可以使用普通文本格式,但解析起来就复杂了,并且不够灵活,因此推荐使用json。loaddata.py大概是这样:
from optparse import make_option
from django.core.management.base import BaseCommand
from django.db.models import get_apps
from django.utils import simplejson as json
from pymongo.objectid import ObjectId
class Command(BaseCommand):
help = 'Installs the named fixture(s) in the database.'
args = "fixture [fixture ...]"
option_list = BaseCommand.option_list + (
make_option('--database', action='store', dest='database',
default='default db', help='Nominates a specific database to load '
'fixtures into. Defaults to the "default" database.'),
)
def handle(self, *fixture_labels, **options):
app_fixtures = [os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in get_apps()]
for fixture_label in fixture_labels:
for fixture_dir in app_fixtures:
fullpath = os.path.join(fixture_dir, fixture_label)
if os.path.isfile(fullpath):
fixture = open(fullpath, 'r')
data = norm_object(json.loads(fixture.read()))
self._do_load(data)
由于json只有几种int, string, bool, array, dict几种数据类型,若是要代表datetime, ObjectId(这是mongodb中ID默认使用的类型)等复杂类型,就需要使用特别的表达方式,例如对datetime可以使用 { '$date': '2009/8/3 05:07:23' },对ObjectId可以使用 { '$oid': 'xxxxx' }来表示,这就需要做某种转换,这是在norm_object中完成的:
def norm_object(data):
if isinstance(data, dict):
if data.has_key('$oid'): # ObjectId
return ObjectId(data[u'$oid'])
if data.has_key('$date'): # datetime
return parse_datetime(data['$date'])
if data.has_key('$ref'): #dbref
from pymongo.dbref import DBRef
return DBRef(data['$ref'], ObjectId(data['$id']))
if isinstance(data, dict):
return dict( [ (norm_object(k), norm_object(v)) for k, v in data.iteritems() ])
if isinstance(data, list):
return [ norm_object(o) for o in data ]
return data
对于_do_load方法,就是使用将fixture中的数据加载到mongodb中,没什么好说的。唯一需要说明的,就是如果指定将数据加载到哪个collection,我在fixture中每项数据中,除了需要加载到数据库的部分,还额外有个_collection属性,用来表明加载到哪个collection。一个用户数据的fixture可能会是这个样子:
[
{
"_collection": "user",
"_id" : { "$oid", "000011112222333344440001" },
"username" : "marlon",
"email" : "marlon@163.com",
"password" : "sha1$6f90a$a1d2d0526aec9338e2d5ab7406315df849d9efdf",
"is_active" : true
}
]
_do_load方法实现如下:
def _do_load(self, data):
db = get_db()
for obj in data:
col = obj.pop('_collection')
col = getattr(db, col)
col.save(obj, save=True)
到此为止,就实现了fixture加载的部分了。要每次运行测试之前加载fixture,在app目录下创建一个fixtures目录,再在其下创建相应的fixture,例如users.json。在TestCase中,fixtures数据指向fixture的文件名称:
class UserTestCase(DjangoTestCase):
fixtures = [ 'users.json', 'other fixture...' ]
另外还需要在运行时创建测试数据库,在测试运行完成之后drop掉数据库。实现起来也很容易,只需要覆盖DjangoTestSuiteRunner的setup_databases和teardown_databases方法就可以了。
class MongoTestSuiteRunner(DjangoTestSuiteRunner):
def setup_databases(self, **kwargs):
self._test_dbname = 'test_' + settings.MONGODB_NAME
settings.MONGODB_NAME = self._test_dbname
# do some database intialize work here
# ...
return super(MongoTestSuiteRunner, self).setup_databases(**kwargs)
def teardown_databases(self, old_config, **kwargs):
conn = get connection ...
print 'drop mongo database %s...' % self._test_dbname
conn.drop_database(self._test_dbname)
super(MongoTestSuiteRunner, self).teardown_databases(old_config, **kwargs)
最后还需要在settings.py中指定testrunner为MongoTestSuiteRunner:
TEST_RUNNER = 'project.utils.test.SATestSuiteRunner'
完成这些工作之后就可以直接使用DjangoTestCase来写单元测试了,我就不教怎么写了。
分享到:
相关推荐
ruoyi-vue-pro-vben 芋道管理后台,基于 vben 最新版本,最新的 vue3 vite4 ant-design-vue 4.0 typescript 语法进行重构开发,支持 springboot3 springcloud 版本
那些年,与你同分同位次的同学都去了哪里?全国各大学在四川2020-2024年各专业最低录取分数及录取位次数据,高考志愿必备参考数据
yolo系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值
该项目是一个基于Java语言开发的水果管理系统设计源码,包含53个文件,其中包括30个Java源文件、13个XML配置文件、6个JAR包文件、1个Git忽略文件、1个属性文件以及1个SQL脚本文件。此系统旨在用于期末答辩展示,展示了开发者对Java编程和系统设计的深入理解。
java回顾、知识整理、拾遗、面试_java-review
mysql主从复制用struts2,spring,hibernate框架,搭建在线考试系统。网站支持(1)老师创建题库,创建题目,查看题目对题目进行增删改,发布考试(选择考试难中易比例),批改学生试卷,查看学生成绩。(.zip
一个基于Go语言实现的搜索引擎项目资源
那些年,与你同分同位次的同学都去了哪里?全国各大学在四川2020-2024年各专业最低录取分数及录取位次数据,高考志愿必备参考数据
基于grpc开发的跨语言的交互系统,集成BCS,Brower
那些年,与你同分同位次的同学都去了哪里?全国各大学在四川2020-2024年各专业最低录取分数及录取位次数据,高考志愿必备参考数据
那些年,与你同分同位次的同学都去了哪里?全国各大学在四川2020-2024年各专业最低录取分数及录取位次数据,高考志愿必备参考数据
那些年,与你同分同位次的同学都去了哪里?全国各大学在四川2020-2024年各专业最低录取分数及录取位次数据,高考志愿必备参考数据
基于go语言,使用gocv和socket实现摄像头视频传输项
apache-seatunnel-web-1.0.2
内容概要:本篇文章主要介绍了如何在VMware虚拟化平台上搭建并配置QNX Neutrino实时操作系统的步骤方法。文章首先给出了获取必要的安装文件来源,然后逐步指导用户如何完成QNX在虚拟机中的安装过程以及相关网络参数配置,包括选择适当的网络模式来实现宿主机器与QNX虚拟机之间的通信,具体为设置NAT模式或者桥接模式下的网络参数,如指定静态或动态获取IP地址的方法。 适用人群:对嵌入式开发感兴趣的技术人士,尤其是需要在Linux环境下开展工作的程序员和系统工程师。 使用场景及目标:通过详细的操作指南帮助初学者快速掌握在Windows或Linux主机上利用虚拟机搭建QNX Real-Time Operating System开发环境的基础技能,能够实现在该环境中运行简单的C/C++应用程序。 其他说明:本文不仅适用于QNX初学者作为入门引导资料,也为经验丰富的开发者提供了有关于特定环境配置的重要参考。由于涉及到的具体细节比较多,读者最好边操作边对照文章内容进行练习。同时要注意保持最新版本的虚拟化平台客户端和服务端程序以确保兼容性和稳定性。
stm32中dma结合ad的使用
yolo系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值
低全球变暖潜能值 (GWP) 制冷剂.docx
那些年,与你同分同位次的同学都去了哪里?全国各大学在四川2020-2024年各专业最低录取分数及录取位次数据,高考志愿必备参考数据
ubuntu