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

S.j*_*kib 5 python django tdd mocking 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})
Run Code Online (Sandbox Code Playgroud)

但是当我尝试使用patchfrom模拟模型类和表单类时会出现问题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)
Run Code Online (Sandbox Code Playgroud)

当我运行测试时,我收到如下错误:

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
Run Code Online (Sandbox Code Playgroud)

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

hj2*_*j24 2

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

原因是:

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

在 django 1.11 iri_to_uri 中,强制 iri 为字节 return quote(force_bytes(iri), safe="/#%[]=:;$&()+,!? @'~") 现在是 return quote(iri, safe="/#%[]=:;$&()+,!? @'~")。

所以解决方案是在lists.views.py中返回redirect(str(list_.get_absolute_url()))而不是返回redirect(list_)

这是我的例子:

def new_list(request):
    form = ItemForm(data=request.POST)
    if form.is_valid():
        list_ = List()
        list_.owner = request.user
        list_.save()
        form.save(for_list=list_)
        return redirect(str(list_.get_absolute_url()))
    else:
        return render(request, 'home.html', {"form": form})
Run Code Online (Sandbox Code Playgroud)