Насмешливая форма в представлении на основе класса без использования MagicMock

Я боролся с насмешкой над классом формы, чтобы заменить его экземпляр в представлении на основе классов. Но это выглядит так, потому что форма находится в атрибуте класса, это происходит до того, как я заменяю класс формы своим макетом. Дело в точке:

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

приложение/тесты/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 и переопределил переменную form с помощью pdb, что сделало мой тест пройденным.

Похоже, что по какой-то причине SomeViewClass [зарегистрировано, создано,...] до того, как я начну исправлять SomeForm. Любые идеи по этому поводу?


person Wonskcalb    schedule 10.01.2019    source источник
comment
Как насчет того, чтобы сделать @patch('app.views.SomeForm.form')?   -  person Daniel Roseman    schedule 10.01.2019
comment
@DanielRoseman form является атрибутом SomeViewClass, а не SomeForm   -  person foxyblue    schedule 10.01.2019
comment
@DanielRoseman Вот оно! Большое спасибо. Хотя foxyblue находится прямо на месте атрибута. Не могли бы вы дать мне ответ, чтобы подтвердить это?   -  person Wonskcalb    schedule 10.01.2019


Ответы (1)


Проблема в том, что представление уже загружено Django, а поле form уже определено и указывает на производственный класс SomeForm.

Как отметили в своих комментариях @DanielRoseman и @foxyblue, можно напрямую исправить поле в классе. И на самом деле на SO уже был ответ на этот вопрос. Как уже отмечалось, можно использовать patch.object для исправления члена класса (это, 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
person Wonskcalb    schedule 11.01.2019