基于 class 的视图中的模拟表单不使用 MagicMock
Mocking form in class based view not using the MagicMock
我一直在努力模拟一个表单 class 以在基于 class 的视图中替换它的一个实例。但看起来是这样,因为表单位于 class 属性中,它发生在 before 我用我的模拟替换了表单 class。例证:
app/views.py
from app.forms import SomeForm # For some reason, this _is_ my mock...
class SomeViewClass(View):
form = SomeForm # ... while this is the _real_ SomeForm
def post(self, request):
form = self.form(request.POST, request.FILES)
# Hacked around with pdb here
# (Pdb) self.form = SomeForm <-- Force the mock into the object
# (Pdb) form = self.form(request.POST, request.FILES)
# (Pdb) form.is_valid() is now True
# (Pdb) continue <--- Test finishes, and asserts are OK.
if form.is_valid(): # This fails, as I'm running the real code
# code, code, code
app/tests/test_views.py
from mock import MagicMock, patch
from django.tests import Client, TestCase
@patch('app.views.SomeForm')
def test_post_valid_form_should_pass(self, mocked_form_class):
""" Replacing SomeForm in SomeViewClass to pas the is_valid test
"""
form_instance = MagicMock(spec=SomeForm())
form_instance.is_valid.return_value = True
mocked_form_class.return_value = form_instance
self.client.login(**self.credentials)
# code, code, code
正如您在app/views.py
中插入的评论中看到的那样,我强行重新加载self.form
并使用pdb重新定义了变量form
,这使我的测试通过了。
似乎由于某种原因,SomeViewClass
在我开始修补 SomeForm
之前 [已注册,实例化,...]。有什么想法吗?
问题是视图已经被 Django 加载并且 form
字段已经定义并指向 SomeForm
production class.
正如@DanielRoseman 和@foxyblue 在他们的评论中指出的那样,可以直接修补 class 中的字段。实际上 there was already an answer for that on SO. As pointed out, it is possible to use patch.object
to patch a member of a class(在我看来,这是最好的解决方案,因为它更明确,而且更不容易出现拼写错误)
测试更正:
和patch
@patch('app.views.SomeView.form', autospec=SomeForm)
def test_post_valid_form_should_pass(self, mocked_form_class):
""" Replacing SomeForm in SomeViewClass.form to pass the is_valid test """
mocked_form_class.is_valid.return_value = True
self.client.login(**self.credentials)
# code, code, code
和patch.object
@patch.object(SomeView, 'form', autospec=SomeForm)
def test_post_valid_form_should_pass(self, mocked_form_class):
""" Replacing SomeForm in SomeViewClass.form to pass the is_valid test """
mocked_form_class.is_valid.return_value = True
self.client.login(**self.credentials)
# code, code, code
我一直在努力模拟一个表单 class 以在基于 class 的视图中替换它的一个实例。但看起来是这样,因为表单位于 class 属性中,它发生在 before 我用我的模拟替换了表单 class。例证:
app/views.py
from app.forms import SomeForm # For some reason, this _is_ my mock...
class SomeViewClass(View):
form = SomeForm # ... while this is the _real_ SomeForm
def post(self, request):
form = self.form(request.POST, request.FILES)
# Hacked around with pdb here
# (Pdb) self.form = SomeForm <-- Force the mock into the object
# (Pdb) form = self.form(request.POST, request.FILES)
# (Pdb) form.is_valid() is now True
# (Pdb) continue <--- Test finishes, and asserts are OK.
if form.is_valid(): # This fails, as I'm running the real code
# code, code, code
app/tests/test_views.py
from mock import MagicMock, patch
from django.tests import Client, TestCase
@patch('app.views.SomeForm')
def test_post_valid_form_should_pass(self, mocked_form_class):
""" Replacing SomeForm in SomeViewClass to pas the is_valid test
"""
form_instance = MagicMock(spec=SomeForm())
form_instance.is_valid.return_value = True
mocked_form_class.return_value = form_instance
self.client.login(**self.credentials)
# code, code, code
正如您在app/views.py
中插入的评论中看到的那样,我强行重新加载self.form
并使用pdb重新定义了变量form
,这使我的测试通过了。
似乎由于某种原因,SomeViewClass
在我开始修补 SomeForm
之前 [已注册,实例化,...]。有什么想法吗?
问题是视图已经被 Django 加载并且 form
字段已经定义并指向 SomeForm
production class.
正如@DanielRoseman 和@foxyblue 在他们的评论中指出的那样,可以直接修补 class 中的字段。实际上 there was already an answer for that on SO. As pointed out, it is possible to use patch.object
to patch a member of a class(在我看来,这是最好的解决方案,因为它更明确,而且更不容易出现拼写错误)
测试更正:
和patch
@patch('app.views.SomeView.form', autospec=SomeForm)
def test_post_valid_form_should_pass(self, mocked_form_class):
""" Replacing SomeForm in SomeViewClass.form to pass the is_valid test """
mocked_form_class.is_valid.return_value = True
self.client.login(**self.credentials)
# code, code, code
和patch.object
@patch.object(SomeView, 'form', autospec=SomeForm)
def test_post_valid_form_should_pass(self, mocked_form_class):
""" Replacing SomeForm in SomeViewClass.form to pass the is_valid test """
mocked_form_class.is_valid.return_value = True
self.client.login(**self.credentials)
# code, code, code