测试Django:意外HTTP状态码的原因
我们在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的测试客户端更像是集成测试,而不是单元测试,因为它会测试网址路由、数据库、中间件、模板等等。