繁体   English   中英

Django / Python单元测试:如何强制Try / Except块的异常

[英]Django/Python unittesting: How to Force Exception of Try/Except Block

有什么方法可以强制执行except块,以便我可以通过单元测试验证错误消息/处理? 例如:

views.py

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块,因此我正在寻求任何帮助。

您可以使用unittest.mock来完成。 您应该通过patch.object修补Books.objects对象,并使用side_effect引发异常。 对方法异常行为的完整测试应为:

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确实删除了字符串依赖性。 我不确定要在代码中测试什么(完整的行为或只是重定向...),无论如何,我写了一个完整的示例。


如果您的项目不是遗留项目,请考虑以TDD风格重写您的方法(以及新的django的ORM调用),例如,您有一个_get_books_proxy()函数,该函数仅调用django的ORM方法:

def _get_books_proxy(request):
    return Books.objects.get_or_create(user=request.user)

现在,由patch装饰器直接将_get_books_proxy() patch为:

@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()来测试_get_books_proxy()行为:

@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)

现在您有了一个哨兵,如果您的关键点行为将被更改,您将可以屈服。

如果您发现一些错误(我无法测试),我深表歉意。但是我希望这个主意很清楚。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM