我从来没有在我的生活中写过任何测试,但我想开始为我的Django项目编写测试.我已经阅读了一些关于测试的文章,并决定尝试为一个非常简单的Django应用程序或者开始编写一些测试.
该应用程序有两个视图(列表视图和详细信息视图)和一个包含四个字段的模型:
class News(models.Model):
title = models.CharField(max_length=250)
content = models.TextField()
pub_date = models.DateTimeField(default=datetime.datetime.now)
slug = models.SlugField(unique=True)
Run Code Online (Sandbox Code Playgroud)
我想向您展示我的tests.py文件并询问:
是否有意义?
我甚至在测试正确的东西吗?
是否有我不遵循的最佳实践,你可以指点我吗?
我的tests.py(它包含11个测试):
# -*- coding: utf-8 -*-
from django.test import TestCase
from django.test.client import Client
from django.core.urlresolvers import reverse
import datetime
from someproject.myapp.models import News
class viewTest(TestCase):
def setUp(self):
self.test_title = u'Test title: b?rek??'
self.test_content = u'This is a content 156'
self.test_slug = u'test-title-bareksc'
self.test_pub_date = datetime.datetime.today()
self.test_item = News.objects.create(
title=self.test_title,
content=self.test_content,
slug=self.test_slug,
pub_date=self.test_pub_date,
)
client = Client()
self.response_detail = client.get(self.test_item.get_absolute_url()) …Run Code Online (Sandbox Code Playgroud) 我正在使用python对象指定数据库:
DATABASES = {
'default':{
'ENGINE':'mysql',
'NAME':'testsqldb',
'USER':'<username>',
'PASSWORD':'<password>',
},
'dynamic_data':{
'ENGINE': 'sqlite3',
'NAME':'',
'USER':'',
'PASSWORD':''
},
}
Run Code Online (Sandbox Code Playgroud)
如何指定测试数据库的名称?我一直试图TEST_NAME = 'auto_tests'在settings.py文件中使用.但是,当我运行时,python manage.py tests <app_name>我收到以下消息:
Creating test database 'default'...
Got an error creating the test database: (1007, "Can't create database 'test_testsqldb'; database exists")
Type 'yes' if you would like to try deleting the test database 'test_testsqldb', or 'no' to cancel:
Run Code Online (Sandbox Code Playgroud)
我希望系统在运行我的测试时创建一个单独的数据库,大概叫做'auto_tests_testsqldb'; 但是,它还在问我关于test_testsqldb的问题.
任何建议表示赞赏!
我正在针对一个API编写一些单元测试,该API要么返回所有书籍,要么只返回查询参数中给定类型的书籍.当我在本地开发服务器中点击它时,这似乎正常.但是,如果在我的单元测试中指定了类型,它甚至不会进入else语句.
我的单元测试看起来像这样:
class TitlesAndBlurbsListTestCase(APITestCase):
def setUp(self):
# Creates a lot of books with genre horror
# and books not in the horror genre
def test_horror_genre(self):
# Ensure that screener can see all the available books
self.client.login(username='b', password='b')
response = self.client.get('/api/titles-and-blurbs/?genre=horror')
self.assertEqual(response.status_code, status.HTTP_200_OK)
# Ensure that the screener gets all horror books at first
horror_books = TitlesAndBlurbs.objects.filter(genre='horror')
# I keep getting an assertion error here - it returns all the books
self.assertEqual(len(response.data), horror_books.count())
Run Code Online (Sandbox Code Playgroud)
我的api视图看起来像这样
class TitlesAndBlurbsListViewSet(viewsets.mixins.ListModelMixin,
viewsets.mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
model = TitlesAndBlurbs …Run Code Online (Sandbox Code Playgroud) 我正在尝试测试我的Django视图.此视图将QuerySet传递给模板:
def merchant_home(request, slug):
merchant = Merchant.objects.get(slug=slug)
product_list = merchant.products.all()
return render_to_response('merchant_home.html',
{'merchant': merchant,
'product_list': product_list},
context_instance=RequestContext(request))
Run Code Online (Sandbox Code Playgroud)
并测试:
def test(self):
"Merchant home view should send merchant and merchant products to the template"
merchant = Merchant.objects.create(name='test merchant')
product = Product.objects.create(name='test product', price=100.00)
merchant.products.add(product)
test_client = Client()
response = test_client.get('/' + merchant.slug)
# self.assertListEqual(response.context['product_list'], merchant.products.all())
self.assertQuerysetEqual(response.context['product_list'], merchant.products.all())
Run Code Online (Sandbox Code Playgroud)
编辑
我用的是self.assertQuerysetEqual而不是self.assertListEqual.不幸的是,这仍然无效,终端显示:
['<Product: Product object>'] != [<Product: Product object>]
assertListEqual提出:'QuerySet' object has no attribute 'difference'并且
assertEqual也不起作用,虽然self.assertSetEqual(response.context['product_list'][0], …
所以我有各种各样的信号和处理程序,它们通过应用程序发送.但是,当我执行测试/进入"测试模式"时,我希望禁用这些处理程序.
在测试模式下是否有一种特定于Django的禁用信号/处理程序的方法?我可以想到一个非常简单的方法(在if TESTING子句中包含处理程序)但我想知道Django中是否有更好的方法?...
我需要MockMixin为我的测试创建一些.它应该包括调用外部源的所有内容的模拟.例如,每次我在管理面板中保存模型时,我都会调用一些远程URL.如果嘲笑并使用那样的话会很好:
class ExampleTestCase(MockedTestCase):
# tests
Run Code Online (Sandbox Code Playgroud)
因此,每次我在管理员中保存模型时,例如在功能测试中,应用此模拟而不是调用远程URL.
这有可能吗?我能够为1个特定测试做到这一点,这不是问题.但是有一些全局模拟更有用,因为我经常使用它.
我正在尝试为一些具有FileField的模型构建测试.该模型如下所示:
class SolutionFile(models.Model):
'''
A file from a solution.
'''
solution = models.ForeignKey(Solution)
file = models.FileField(upload_to=make_solution_file_path)
Run Code Online (Sandbox Code Playgroud)
我遇到了两个问题:
使用时将数据保存到夹具时./manage.py dumpdata,不保存文件内容,只将文件名保存到夹具中.虽然我发现这是预期的行为,因为文件内容没有保存到数据库中,我想以某种方式将这些信息包含在夹具中进行测试.
我有一个用于上传文件的测试用例,如下所示:
def test_post_solution_file(self):
import tempfile
import os
filename = tempfile.mkstemp()[1]
f = open(filename, 'w')
f.write('These are the file contents')
f.close()
f = open(filename, 'r')
post_data = {'file': f}
response = self.client.post(self.solution.get_absolute_url()+'add_solution_file/', post_data,
follow=True)
f.close()
os.remove(filename)
self.assertTemplateUsed(response, 'tests/solution_detail.html')
self.assertContains(response, os.path.basename(filename))
Run Code Online (Sandbox Code Playgroud)虽然此测试工作正常,但在完成后将上传的文件保留在媒体目录中.当然,删除可以照顾tearDown(),但我想知道Django是否有另一种处理方式.
我想到的一个解决方案是使用不同的媒体文件夹进行测试,必须与测试夹具保持同步.有没有办法在settings.py运行测试时指定另一个媒体目录?我可以在dumpdata中包含某种钩子,以便同步媒体文件夹中的文件吗?
那么,是否有更多的Pythonic或Django特定方式处理涉及文件的单元测试?
我正在加载使用dumpdata创建的fixture,并获得以下异常:
Problem installing fixture 'db_dump.json': Traceback (most recent call last):
File "/usr/lib/python2.6/site-packages/django/core/management/commands/loaddata.py", line 174, in handle
obj.save(using=using)
File "/usr/lib/python2.6/site-packages/django/core/serializers/base.py", line 165, in save
models.Model.save_base(self.object, using=using, raw=True)
File "/usr/lib/python2.6/site-packages/django/db/models/base.py", line 526, in save_base
rows = manager.using(using).filter(pk=pk_val)._update(values)
File "/usr/lib/python2.6/site-packages/django/db/models/query.py", line 491, in _update
return query.get_compiler(self.db).execute_sql(None)
File "/usr/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 869, in execute_sql
cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)
File "/usr/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 735, in execute_sql
cursor.execute(sql, params)
File "/usr/lib/python2.6/site-packages/django/db/backends/sqlite3/base.py", line 234, in execute
return Database.Cursor.execute(self, query, params)
IntegrityError: columns app_label, model are not unique
Run Code Online (Sandbox Code Playgroud)
这是一个sqlite3后端.
更新:使用自然键在这里没有区别. …
我有以下django测试用例,它给了我错误:
class MyTesting(unittest.TestCase):
def setUp(self):
self.u1 = User.objects.create(username='user1')
self.up1 = UserProfile.objects.create(user=self.u1)
def testA(self):
...
def testB(self):
...
Run Code Online (Sandbox Code Playgroud)
当我运行我的测试时,testA将成功通过但在testB启动之前,我收到以下错误:
IntegrityError: column username is not unique
Run Code Online (Sandbox Code Playgroud)
很明显,它试图self.u1在每个测试用例之前创建并发现它已经存在于数据库中.如何在每个测试用例之后正确清理它以便后续情况正确运行?
我想像调试任何其他Python代码一样调试Django TestCase:只需调用pdb.set_trace()然后进入交互式会话即可.当我这样做时,我没有看到任何东西,因为测试是在不同的过程中运行的.我正在使用django-discover-runner,但我的猜测是这适用于默认的Django测试运行器.
是否可以在每次错误/失败pdb时使用django-discover-runnera)进入会话,和/或b)只有在我调用pdb.set_trace()我的测试代码时?
这个答案解释了Django创建了另一个进程,并建议使用rpdb2 debugger一部分调用winpdb,但我不想使用winpdb,我宁愿使用ipdb.
这个答案django-nose通过运行如下所示的测试命令解决了问题:./manage.py test -- -s但该选项不可用django-discover-runner.
这个答案显示我可以这样做ipython:
In [9]: %pdb
Automatic pdb calling has been turned ON
Run Code Online (Sandbox Code Playgroud)
这似乎是一个潜在的选择,但ipython每次运行测试时启动它似乎有点麻烦.
最后,这个答案表明nose带有一个--pdb标志,它会pdb出现错误,这就是我想要的.我唯一的选择是切换到django-nose测试跑步者?
我在内置帮助中没有看到任何选项django-discover-runner:
$ python manage.py help test --settings=settings.test
Usage: manage.py test [options] [appname ...]
Runs …Run Code Online (Sandbox Code Playgroud) django ×10
django-testing ×10
python ×5
unit-testing ×5
debugging ×1
filefield ×1
pdb ×1
python-mock ×1
settings ×1
testing ×1