Django 测试客户端不处理异常?
Django test client does not handle exceptions?
我需要使用 Django 测试虚拟客户端为 Django 中的自定义 handler404 和 handler500 编写一些测试。
第一个很容易测试,而第二个我有问题。
基本上,问题是 Django 测试客户端没有捕获异常并且没有路由到正确的处理程序。这是一个问题,因为我们需要测试是否使用了正确的自定义处理程序和模板。
我们有一个简单的中间件class来模拟测试异常:
class HTTPStatusCodeMiddleware(object):
def process_view(self, request, *args):
if 'cookie_500_error' in request.COOKIES:
raise Exception('Test exception')
上面的代码适用于在浏览器中进行手动测试。
现在,测试是:
def test_404_template(self):
c = Client()
url = '/not_existing.html'
response = c.get(url)
self.assertEqual(response.status_code, 404) # success
self.assertTemplateUsed(response, 'custom/404.html') # success
def test_500_template(self):
c = Client()
c.cookies['cookie_500_error'] = '1'
response = c.get('/') # here middleware raises exception!!!
self.assertEqual(response.status_code, 500)
self.assertTemplateUsed(response, 'custom/500.html')
有什么想法吗?
我没有使用硒的选项。
谢谢!
Django 测试客户端仅处理一些异常(参见 the docs)。所有其他的在测试中都是可见的,你可以测试它们;)
所以 django 测试客户端 class 没有设计来捕获异常,这是一件好事。
由于问题具体是测试自定义 handler500,它是由自定义中间件在特定设置上设置的,只需将 request.urlconf 变量替换为自定义 urlconf 模块,解决方案是使用 RequestFactory 构建请求,并测试 request.urlconf.handler500 视图:
在custom/client1/urls.py
def handler500(request):
data = {'client', 'client1 is sorry!'}
ctx = RequestContext(request)
content = render_to_string('client1/500.html', data, ctx)
return http.HttpResponseServerError(content)
在tests/views/test_error_pages.py
def test_500_template(self):
req = RequestFactory().get('/')
req.user = AnonymousUser()
req.session = {}
cust_mw = CustomUrlconfMiddleware()
cust_mw.process_request(req) # set the custom request.urlconf
urlconf = importlib.import_module(req.urlconf)
response = urlconf.handler500(req)
self.assertEqual(response.status_code, 500)
assert_str = '/static/img/custom/client1/'
self.assertTrue(assert_str in response.content,
msg='500 template is not for client1. String {} is not in content'.format(assert_str))
好吧,我只是 运行 在我的单元测试中使用 PermissionDenied
异常遇到了类似的问题。由于 Django 没有捕获它们,因此导致我的测试崩溃而不是失败。我确实找到了一个我还没有看到的简单解决方案,它是这样的:
示例视图:
from django.core.exceptions import PermissionDenied
class SampleView(object):
def setup(request):
if not request_is_authenticated(request):
raise PermissionDenied
单元测试:
from django.core.exceptions import PermissionDenied
def test_permission(self):
try:
SampleView.setup(request)
except PermissionDenied:
print('Hallelujah no crashing!')
Django 3.0 现已支持此功能
新测试 Client
参数 raise_request_exception
允许控制在请求期间引发的异常是否也应在测试中引发。为了向后兼容,该值默认为 True
。如果是 False
并且发生异常,测试客户端将 return 具有属性 exc_info
的 500 响应,一个提供发生异常的信息的元组。
c = Client(raise_request_exception=False)
有关信息,请访问 documentation
对于 Django 2.x,可以通过修补其 store_exc_info
方法来阻止测试客户端引发异常:
c = Client()
c.store_exc_info = lambda *args, **kw: None
response = c.get("/error")
assert response.status_code == 500
假设处理 /error
url 的视图引发异常,这将允许我们获得 500 Server Error
响应。
对于 Django>=3.0,应该使用 raise_request_exception
参数(如@CesarCanassa 回答中所述)
我需要使用 Django 测试虚拟客户端为 Django 中的自定义 handler404 和 handler500 编写一些测试。 第一个很容易测试,而第二个我有问题。
基本上,问题是 Django 测试客户端没有捕获异常并且没有路由到正确的处理程序。这是一个问题,因为我们需要测试是否使用了正确的自定义处理程序和模板。
我们有一个简单的中间件class来模拟测试异常:
class HTTPStatusCodeMiddleware(object):
def process_view(self, request, *args):
if 'cookie_500_error' in request.COOKIES:
raise Exception('Test exception')
上面的代码适用于在浏览器中进行手动测试。
现在,测试是:
def test_404_template(self):
c = Client()
url = '/not_existing.html'
response = c.get(url)
self.assertEqual(response.status_code, 404) # success
self.assertTemplateUsed(response, 'custom/404.html') # success
def test_500_template(self):
c = Client()
c.cookies['cookie_500_error'] = '1'
response = c.get('/') # here middleware raises exception!!!
self.assertEqual(response.status_code, 500)
self.assertTemplateUsed(response, 'custom/500.html')
有什么想法吗? 我没有使用硒的选项。 谢谢!
Django 测试客户端仅处理一些异常(参见 the docs)。所有其他的在测试中都是可见的,你可以测试它们;)
所以 django 测试客户端 class 没有设计来捕获异常,这是一件好事。
由于问题具体是测试自定义 handler500,它是由自定义中间件在特定设置上设置的,只需将 request.urlconf 变量替换为自定义 urlconf 模块,解决方案是使用 RequestFactory 构建请求,并测试 request.urlconf.handler500 视图:
在custom/client1/urls.py
def handler500(request):
data = {'client', 'client1 is sorry!'}
ctx = RequestContext(request)
content = render_to_string('client1/500.html', data, ctx)
return http.HttpResponseServerError(content)
在tests/views/test_error_pages.py
def test_500_template(self):
req = RequestFactory().get('/')
req.user = AnonymousUser()
req.session = {}
cust_mw = CustomUrlconfMiddleware()
cust_mw.process_request(req) # set the custom request.urlconf
urlconf = importlib.import_module(req.urlconf)
response = urlconf.handler500(req)
self.assertEqual(response.status_code, 500)
assert_str = '/static/img/custom/client1/'
self.assertTrue(assert_str in response.content,
msg='500 template is not for client1. String {} is not in content'.format(assert_str))
好吧,我只是 运行 在我的单元测试中使用 PermissionDenied
异常遇到了类似的问题。由于 Django 没有捕获它们,因此导致我的测试崩溃而不是失败。我确实找到了一个我还没有看到的简单解决方案,它是这样的:
示例视图:
from django.core.exceptions import PermissionDenied
class SampleView(object):
def setup(request):
if not request_is_authenticated(request):
raise PermissionDenied
单元测试:
from django.core.exceptions import PermissionDenied
def test_permission(self):
try:
SampleView.setup(request)
except PermissionDenied:
print('Hallelujah no crashing!')
Django 3.0 现已支持此功能
新测试 Client
参数 raise_request_exception
允许控制在请求期间引发的异常是否也应在测试中引发。为了向后兼容,该值默认为 True
。如果是 False
并且发生异常,测试客户端将 return 具有属性 exc_info
的 500 响应,一个提供发生异常的信息的元组。
c = Client(raise_request_exception=False)
有关信息,请访问 documentation
对于 Django 2.x,可以通过修补其 store_exc_info
方法来阻止测试客户端引发异常:
c = Client()
c.store_exc_info = lambda *args, **kw: None
response = c.get("/error")
assert response.status_code == 500
假设处理 /error
url 的视图引发异常,这将允许我们获得 500 Server Error
响应。
对于 Django>=3.0,应该使用 raise_request_exception
参数(如@CesarCanassa 回答中所述)