测试Django:意外HTTP状态码的原因

3 投票
3 回答
1388 浏览
提问于 2025-04-18 11:43

我们在Django应用中有很多单元测试。

但是如果测试失败了,是因为状态码不匹配:

Traceback (most recent call last):
  File "/home/foo_eins_di514/src/foo-time/foo_time/tests/EditTest.py", line 813, in test_web_entry_with_unclassified_activity
    self.assertEqual(200, response.status_code, url)
  File "/usr/lib64/python2.7/unittest/case.py", line 494, in assertEqual
    assertion_func(first, second, msg=msg)
  File "/usr/lib64/python2.7/unittest/case.py", line 487, in _baseAssertEqual
    raise self.failureException(msg)
AssertionError: /foo_eins_di514/modtime/calendar/entry/view/172/

……那么完全不知道错误的退出状态是在哪里产生的。

在大型应用中,找到问题的根源可能需要一些时间,因为退出状态也可能是在中间件中产生的。

有没有什么建议可以让这个测试更容易一些呢?

这个测试看起来是这样的:

url=reverse(view_name, kwargs=dict(id=entry.id))
response=client.get(url)
self.assertEqual(200, response.status_code, url)

3 个回答

2

我用这个方法来找出问题所在:

import django
django.http.response.HttpResponseBase.__init__=None
response=client.get(url)

这样做会产生一个堆栈跟踪,让我能看到HttpResponse是在哪里创建的。

当然,这只是一个临时的调试方法。我也尝试过用模拟(mock),但因为我还不是模拟方面的专家,所以没有成功。

4

你把 assertEqual 的有用信息换成了一个不太有用的信息,也就是失败的 URL(这是 assertEqual 的第三个参数)。

这样做是因为同一个测试方法测试了多个 URL。这其实是不太好的做法。每个测试方法应该只测试一件事情。DRY(不要重复自己)在单元测试中并不适用,或者说,更重要的是每个测试方法只测试一件事。

假设你知道了出问题的状态码,那就更容易找到问题的来源。如果状态码是 404,那可能是找不到对象;如果是 300 多的状态码,可能是你没有权限,正在被重定向到登录页面。

任何真正的编程错误都会以正常的异常和有用的堆栈跟踪信息失败。

如果你关心某个视图中的逻辑,可以把逻辑拆分成多个可测试的单元。

在这种情况下,我觉得问题可能出在主键不正确或者缺少权限上。

关于你的模拟,可以试试这样的:

with patch.object(HttpResponseBase, '__init__', None):
    response = client.get(url)
4

听起来你应该把你的测试分成合适的单元测试,测试更小的代码部分。可以使用Django的请求工厂,只测试视图代码。或者把你的视图拆分成更小的函数,单独测试它们。

使用Django的测试客户端更像是集成测试,而不是单元测试,因为它会测试网址路由、数据库、中间件、模板等等。

撰写回答