Django模型类被模拟时无法重定向

时间:2018-02-10 11:03:43

标签: python django mocking tdd python-unittest

我在这里有一个视图,它将新的List添加到数据库并重定向到List页面。我在模型类中配置了get_absolute_url。它似乎完美无缺。

def new_list(request):
    form = ItemForm(request.POST)

    if form.is_valid():
        list_ = List()
        list_.owner = request.user
        list_.save()
        form.save(for_list=list_)
        return redirect(list_)
    else:
        return render(request, 'home.html', {'form': form})

但是当我尝试使用patch

中的unitest.mock来模拟模型类和表单类时,会出现问题
class TestMyLists(TestCase):

    @patch('lists.views.List')
    @patch('lists.views.ItemForm')
    def test_list_owner_is_saved_if_user_is_authenticated(
        self, mockItemFormClass, mockListClass
    ):
        user = User.objects.create(email='a@b.com')
        self.client.force_login(user)
        self.client.post('/lists/new', data={'text': 'new item'})
        mock_list = mockListClass.return_value
        self.assertEqual(mock_list.owner, user)

当我运行测试时,我得到这样的错误:

Traceback (most recent call last):
File "/home/sjsakib/.virtualenvs/superlists/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
  response = get_response(request)
File "/home/sjsakib/.virtualenvs/superlists/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
  response = self.process_exception_by_middleware(e, request)
File "/home/sjsakib/.virtualenvs/superlists/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
  response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/mnt/BAC4BB93C4BB4FFD/codes/tdd/superlists/lists/views.py", line 36, in new_list
  return redirect(list_)
File "/home/sjsakib/.virtualenvs/superlists/lib/python3.6/site-packages/django/shortcuts.py", line 58, in redirect
  return redirect_class(resolve_url(to, *args, **kwargs))
File "/home/sjsakib/.virtualenvs/superlists/lib/python3.6/site-packages/django/http/response.py", line 407, in __init__
  self['Location'] = iri_to_uri(redirect_to)
File "/home/sjsakib/.virtualenvs/superlists/lib/python3.6/site-packages/django/utils/encoding.py", line 151, in iri_to_uri
  return quote(iri, safe="/#%[]=:;$&()+,!?*@'~")
File "/usr/local/lib/python3.6/urllib/parse.py", line 787, in quote
  return quote_from_bytes(string, safe)
File "/usr/local/lib/python3.6/urllib/parse.py", line 812, in quote_from_bytes
  raise TypeError("quote_from_bytes() expected bytes")
TypeError: quote_from_bytes() expected bytes

似乎重定向函数不能用于模拟对象。我怎样才能解决这个问题? 我正在使用Django 2.0.1

3 个答案:

答案 0 :(得分:0)

我正在经历与您相同的tutorial,并且“ quote_from_bytes()预期的字节数”错误也给我带来了问题。作者使用的是django 1.11,显然重定向和渲染在模拟方面起到了很好的作用。

为此,我的解决方案是在导致问题的时候模拟重定向和渲染功能。例如,这会导致错误,因为它将导致重定向被调用:

def test_passes_POST_data_to_NewListForm(self, mockNewListForm):
    response = new_list2(self.request)
    mockNewListForm.assert_called_once_with(data=self.request.POST)

但是,当我们模拟重定向时,不会调用Django的重定向,并且不会出现错误:

@patch('lists.views.redirect')
def test_passes_POST_data_to_NewListForm(
    self, mock_redirect, mockNewListForm
):
    response = new_list2(self.request)
    mockNewListForm.assert_called_once_with(data=self.request.POST)

答案 1 :(得分:0)

我正在学习相同的教程,并且遇到相同的错误,但是我在这里找到了解决方法:Mock() function gives TypeError in django2

原因是:

Django 2在某些地方不再支持字节串,因此,当视图重定向模拟类列表时,它作为模拟对象运行,并且iri_to_uri django函数引发错误。

在django 1.11中,iri_to_uri强制将iri转换为字节返回引号(force_bytes(iri),safe =“ /#%[] =:; $&()+,!? @'〜”)代替现在是返回引号(iri,safe =“ /#%[] =:; $&()+,!? @'〜”)。

因此解决方案是返回redirect(str(list_.get_absolute_url())),而不是返回list.views.py中的redirect(list _)

这是我的例子:

playerSharedPref!!.getString("name", "")!!

答案 2 :(得分:0)

请参阅我的 answer here,它仅更改测试代码,同时生成所需的生产代码。