Django测试客户端在现有URL上出现404错误

5

我刚开始学习单元测试,遇到了这个问题。

我的项目结构如下(现在是Django 1.6.2):

./manage.py
./myproject
./myproject/urls.py
./myproject/myapp/
./myproject/myapp/urls.py
./myproject/myapp/views.py
./tests/
./test/test_example.py

在./myproject/urls.py文件中,我有以下内容:
from django.conf.urls import patterns, include, url
urlpatterns = patterns('',
    url(r'^myapp/', include('myproject.myapp.urls')),
)

在./myproject/myapp/urls.py中,我有以下内容:
from django.conf.urls import patterns, url

urlpatterns = patterns('myproject.myapp.views',
    url(r'^example1/$', 'itemlist'),  
    url(r'^example1/(?P<item_id>\w+)/$', 'item'),
)

我编写了基础测试,并将其放入./test/test_example.py中。

import unittest
from django.test import Client

class PagesTestCase(unittest.TestCase): 
    def setUp(self):
        self.client = Client()

    def test_itemlist(self):        
        response = self.client.get('/myapp/example1/')
        self.assertEqual(response.status_code, 200)

    def test_item(self):        
        response = self.client.get('/myapp/example1/100100/')
        self.assertEqual(response.status_code, 200)

我通过以下方式在shell中运行这些测试:

cd ./tests
python manage.py test

第一个测试运行正常,但第二个总是失败并显示“404未找到”状态码。

在浏览器中两个URL都正常工作。

另外,我尝试了这个:

cd ./
python manage.py shell
>>> from django.test.client import Client
>>> c = Client()
>>> r = c.get('/myapp/example1/100100/')
>>> r.status_code
200

我就是无法弄清楚如何正确运行那些测试。似乎没有任何一个作为参数传递给视图的模式对我有效。但是所有固定的URL都能被Django.test.client正确找到。

谢谢!

编辑:我刚发现404在我的myproject/myapp/views.py中触发了

这是一段代码:

def item(request, item_id):
    try:
        item = Item.objects.get(pk = int(item_id))
    except (ValueError, Item.DoesNotExist):     
        raise Http404

这里出现了Item.DoesNotExist异常。我不知道为什么找不到那个项目?


你的数据库中有任何数据吗?如果没有,你应该插入一个或多个测试夹具。 (你的测试数据库与生产数据库分开,所以不用担心删除任何真实数据。) - Platinum Azure
测试数据库与生产数据库是分开的。 啊!明白了。所以那个单元测试的东西有点不同于我原来想的。它不是用来测试生产数据中的错误的。我太傻了 :) - anti1869
对。单元测试是用来测试代码中的错误的。话虽如此,“代码中的错误”应该包括确保在面对不可用或损坏的数据时,代码表现得合理。因此,编写一个特定的单元测试来测试,假定指定ID的项不存在于数据库中,您的视图应该引发“Http404”(假设这是在特定情况下期望的行为),是有绝对价值的。 - Platinum Azure
2个回答

2
除了使用reverse,如果测试数据库中没有预期的模型可用(如评论中所述),您还可以获得404。您应该使用Django的TestCase而不是Python的unittest,因为前者继承自后者,但使与数据库交互更加容易(以及其他事情)。
以下是设置测试数据的示例:
from django.test import TestCase
from django.urls import reverse

# Or whatever your object is.
from .models import Item


class ItemViewsTestCase(TestCase):
    """Tests for Item views."""
    @classmethod
    def setUpTestData(cls):
        """Set up test data available for all tests in this class."""
        cls.item = Item.objects.create(name='Testing')

    def test_item_list_view(self):
        # Note, self.client we get for free from Django's TestCase.
        response = self.client.get(reverse('itemlist'))
        self.assertEqual(response.status_code, 200)

    def test_item_detail_view(self):
        # This url pattern expects an Item.id so use the item we set up.
        url = reverse('item', args=[self.item.id])
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

1
请使用reverse()函数来构建URL,例如:

./myproject/myapp/urls.py文件中,为每个URL模式提供一个名称参数,如下所示:

from django.conf.urls import patterns, url

urlpatterns = patterns('myproject.myapp.views',
    url(r'^example1/$', 'itemlist', name='example-one'),  
    url(r'^example1/(?P<item_id>\w+)/$', 'item', name='example-two'),
)

我们将使用给定的name参数值来构建URL。
然后在./test/test_example.py文件中:
from django.core.urlresolvers import reverse

class PagesTestCase(unittest.TestCase): 
    ...
    def test_itemlist(self):
        url = reverse('example-one')
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

    def test_item(self):
        url = reverse('example-two')    
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

那应该就可以了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接