Django/Python单元测试:如何强制Try/Except块的异常 [英] Django/Python unittesting: How to Force Exception of Try/Except Block
问题描述
是否有任何方法可以强制执行except块,以便我可以通过单元测试来验证错误消息/处理?例如:
Is there any way to force the except block to execute so that I can verify the error messages/handling with unit testing? For example:
def get_books(request):
...
try:
book = Books.objects.get_or_create(user=request.user)
except:
messages.error(request, 'Unable to create new book!')
return HttpResponseRedirect(reverse('my_books'))
# more try/except cases
因此,在此示例中,我可以尝试模拟ORM失败,或者可以尝试为这种情况发送无效的用户.但是是否有引发异常的一般方法(我愿意使用库)?例如 Mock
.还是有其他方法可以使用 unittest
强制异常?显然,整个代码中将有很多try/except块,因此我正在寻求任何帮助.
So in this example, I could try to simulate an ORM failure or I can try to send in an invalid user for this case. But is there a general way to throw exceptions (I'm open to using libraries)? Mock
for instance. Or is there some other method to use unittest
to force exceptions? Obviously there are going to be many try/except blocks throughout the code, so I'm looking for any help.
推荐答案
您可以使用 unittest.mock
进行操作.您应该通过 patch.object
修补 Books.objects
对象,并使用 side_effect
引发异常.对方法异常行为的完整测试应该是:
You can use unittest.mock
to do it. You should patch Books.objects
object by patch.object
and use side_effect
to raise exception. A complete test of your method exception behavior should be:
import unittest
from unittest.mock import patch, ANY
from django.test.client import RequestFactory
class TestDjango(unittest.TestCase):
@patch("your_module.messages")
@patch("your_module.HttpResponseRedirect")
def test_get_books_exception(self,mock_redirect,mock_messages)
r = RequestFactory().get('/I_dont_konw_how_to_build_your_request/')
objs = Books.objects
with patch.object(objs,"get_or_create", side_effect=Exception()):
self.assertIs(get_books(r),mock_redirect.return_value)
mock_messages.error.assert_called_with(r, ANY)
mock_redirect.assert_called_with(reverse('my_books'))
我使用 ANY
确实删除了字符串依赖项.无论如何,我不确定要在代码中测试什么(完整的行为或只是重定向...).
I used ANY
do remove the string dependency. I'm not sure what you want test in your code (complete behavior or just redirect...), anyway I wrote a complete example.
如果您的项目不是遗留项目,请考虑以TDD样式重写您的方法(以及新的django的ORM调用),例如,您有一个 _get_books_proxy()
函数,该函数仅调用django ORM方法:
If your project is not a legacy work consider to rewrite your method (and the new django's ORM calls) in TDD style where you have for instance a _get_books_proxy()
function that just call the django ORM methods:
def _get_books_proxy(request):
return Books.objects.get_or_create(user=request.user)
现在通过 patch
装饰器直接将 _get_books_proxy()
修补为:
and now patch _get_books_proxy()
directly by patch
decorator as:
@patch("your_module.messages")
@patch("your_module.HttpResponseRedirect")
@patch("your_module._get_books_proxy", side_effect=Exception())
def test_get_books_exception(self,mock_get_book, mock_redirect, mock_messages)
r = RequestFactory().get('/I_dont_konw_how_to_build_your_request/')
self.assertIs(get_books(r),mock_redirect.return_value)
mock_messages.error.assert_called_with(r, ANY)
mock_redirect.assert_called_with(reverse('my_books'))
此外,可以通过修补 Books
并传递一个简单的 Mock()
:
Moreover _get_books_proxy()
behavior can be tested by patching Books
and passing a simple Mock()
:
@patch("your_module.Books")
def test__get_books_proxy(self,mock_books):
r = Mock()
self.assertIs(mock_books.objects.get_or_create.return_value, your_module._get_books_proxy(r))
mock_books.objects.get_or_create.assert_called_with(user=r.user)
现在您有了一个哨兵,如果您的关键点行为将被更改,您将可以屈服.
Now you have a sentinel that can yield to you if your critical point behavior will be changed.
如果您发现一些错误(我无法测试),我深表歉意.但是我希望这个主意很清楚.
I apologize if you find some errors (I cannot test it)... but I hope the idea is clear.
这篇关于Django/Python单元测试:如何强制Try/Except块的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!