Django/Python单元测试:如何强制Try/Except块的异常 [英] Django/Python unittesting: How to Force Exception of Try/Except Block

查看:56
本文介绍了Django/Python单元测试:如何强制Try/Except块的异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有任何方法可以强制执行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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆