在基于类的视图中模拟表单不使用MagicMock

时间:2019-01-10 11:16:15

标签: python django django-class-based-views python-mock django-unittest

我一直在努力模拟表单类,以在基于类的视图中替换其实例。但是看起来像这样,因为该表单位于类属性中,所以它发生在之前,我用我的模拟替换了表单类。例子:

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之前已被[注册,实例化...]。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

问题是Django已经加载了视图,并且form字段已经定义并指向SomeForm production 类。

正如@DanielRoseman和@foxyblue在其注释中指出的那样,可以直接在类中修补字段。实际上是there was already an answer for that on SO。如所指出的,可以使用patch.object to patch a member of a class(这是IMO,最好的解决方案,因为它更加明确,并且不太容易出现错字)

测试已纠正:

使用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