【问题标题】:How to test get request in Django with a data?如何在 Django 中使用数据测试获取请求?
【发布时间】:2018-03-02 12:43:54
【问题描述】:

我现在正在 Django 中为我的 Web 应用程序编写测试。我有一个网址127.0.0.1/home/device/(?P<item>[^/]+)。我正在测试无效的 URL 路径。 这里item 是数据库中的设备名称。考虑一个无效的设备,在测试时我给出了以下代码:

response=self.client.get("/health/errorfiles/",{'item':'testdevice_R'})

这会给我一个 404 响应。我尝试过的同样的事情:

response=self.client.get("/health/errorfiles/testdevice_R/")

但这一次,测试运行程序执行了我的视图函数并给出了 TypeError,因为它不是无效设备。

在这两种方法中,哪一种是获取请求的正确用法?

views.py

def showfiles(request,item):

if request.user.is_anonymous():                                                             ## check if the user is valid
    return HttpResponseRedirect("/")

db = MySQLdb.connect(host='localhost',user=root,passwd='123mcvis',db='test_db')

s = db.cursor()                                                                      
username=request.user                                                                     
s.execute("Select tzone,type from device where user='%s' and device='%s'"%(username,item)                     
tz=s.fetchone()
timezone.activate(tz[0])
s.close()
return render(request,"Home/showdevices.html")

这是我的查看功能,由于设备无效,所以显示类型错误。

class showfile_test(TestCase):
     def test_invalid(self):

           response=self.client.get("/health/errorfiles/testdevice_R/")
           self.assertEqual(response.status_code,404)

追溯

   ERROR: test_invalid (HealthApp.tests2.showfile_test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/vishnumc/vishnu/project/django/official/version6.2.3/HealthApp/tests2.py", line 162, in test_showfiles_with_invalid_deviceid
    response=self.client.get("/health/errorfiles/invaliddevice/")
  File "/home/vishnumc/vishnu/project/env/local/lib/python2.7/site-packages/django/test/client.py", line 529, in get
    **extra)
  File "/home/vishnumc/vishnu/project/env/local/lib/python2.7/site-packages/django/test/client.py", line 333, in get
    return self.generic('GET', path, secure=secure, **r)
  File "/home/vishnumc/vishnu/project/env/local/lib/python2.7/site-packages/django/test/client.py", line 409, in generic
    return self.request(**r)
  File "/home/vishnumc/vishnu/project/env/local/lib/python2.7/site-packages/django/test/client.py", line 494, in request
    six.reraise(*exc_info)
  File "/home/vishnumc/vishnu/project/env/local/lib/python2.7/site-packages/django/core/handlers/exception.py", line 39, in inner
    response = get_response(request)
  File "/home/vishnumc/vishnu/project/env/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 249, in _legacy_get_response
    response = self._get_response(request)
  File "/home/vishnumc/vishnu/project/env/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/vishnumc/vishnu/project/env/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/vishnumc/vishnu/project/django/official/version6.2.3/HealthApp/views.py", line 118, in showfiles
    timezone.activate(tz[0])                                                                        ##setting current timezone to user's time zone for display timestamps
TypeError: 'NoneType' object has no attribute '__getitem__'

【问题讨论】:

  • 能否提供更多您的测试文件?你在使用 django 的测试类吗?
  • 是的。我正在使用 TestCase 类
  • @Alasdair 当我请求没有削减结束时,响应是 301
  • 是的,我添加了回溯。
  • @Alasdair ,为了简单起见,我刚刚重命名了为什么发现差异的文件。你现在可以看看吗

标签: python django httpclient django-testing django-unittest


【解决方案1】:

第一个示例是对/health/errorfiles/?item=testdevice_R 的GET 请求。在视图中,您会在request.GET 中找到item。

第二个示例是对/health/errorfiles/testdevice_R/ 的GET 请求。 request.GET 中没有数据,Django 会将 item 传递给您的视图,因为您的 URL 模式中有一个命名组 (?P<item>[^/]+)。

您应该使用第二个版本,因为您要测试 URL 模式 r'/home/device/(?P<item>[^/]+)'。

您的测试的第二个版本发现了您认为的问题。您需要修复视图,使其不会引发TypeError。

理想情况下,您不应该编写这样的原始 SQL。 Django 允许您执行以下操作:

from .models import Device

from django.shortcuts import get_object_or_404, render

def showhome(request, item):
    device = get_object_or_404(Device, user=request.user, item=item)
    if device is not None:
        timezone.activate(device.tzone)
    return render(request,"Home/showdevices.html", {'device': device})

如果您必须使用原始 SQL,则不要使用字符串替换 %(username,item)。您当前的代码会将您暴露给 SQL 注入帐户。您应该将其更改为:

s.execute("Select tzone,type from device where user=%s" and device=%s, (username, item))

然后您的代码将处理tz 为None 的情况,以避免TypeError。

tz = s.fetchone()
if tz is not None:
    timezone.activate(tz[0])
else:
    # Decide what to do if no items returned

【讨论】:

  • 我没有使用 django ORM 或 django 模型。我正在使用 MySQLdb 连接数据库
  • 如果您不使用 ORM,您将忽略 Django 的主要优势之一。您的 execute() 代码不安全并且容易受到 SQL 注入的影响,因为您使用的是字符串替换而不是转义参数。如果您使用上述 ORM,则可以避免该问题。
  • 但是 django ORM 比 MYSQLdb 很慢
  • 在某些情况下,Django ORM 可能很慢,但是对于像这样的简单提取,如果差异很明显,我会感到惊讶。
  • 你错过了s.execute("Select tzone,type from device where user=%s and device=%s, (username, item))中的“”吗?
猜你喜欢
  • 1970-01-01
  • 2012-05-03
  • 1970-01-01
  • 1970-01-01
  • 2018-05-30
  • 1970-01-01
  • 2017-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多