Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django-crispy-form: Unit test fails because of TypeError of helper object

Somewhat based on a chapter of this book, I'd like to unit test a form created with django-crispy-form but I get the following error:

TypeError: helper object provided to {% crispy %} tag must be a crispy.helper.FormHelper object.

The form (myapp/forms.py):

class MyBaseForm(forms.models.ModelForm):

    def __init__(self, *args, **kwargs):
        super(MyBaseForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_id = 'id-myForm'
        self.helper.form_method = 'POST'
        self.helper.form_action = ''
        self.helper.add_input(Submit('submit', 'Create'))

    class Meta:
        model = MyModel
        # [...]

class MyNewForm(MyBaseForm):

    def save(self):
        return MyModel.create_new(data=self.cleaned_data['data'])

The view (myapp/views.py):

@login_required
def event_new(request):
    if request.method == 'POST':
        form = MyNewForm(data=request.POST)
        if form.is_valid():
            event = form.save()
            return redirect(event)
    else:
        form = MyNewForm()
return render(request, 'event_new.html', {'form': form})

The test:

@patch('myapp.views.MyNewForm')
class MyNewViewUnitTest(TestCase):

    def setUp(self):
        self.t = unittest.TestCase()
        self.t.request = HttpRequest()
        self.t.request.POST['data'] = 'data'
        self.t.request.user = Mock()

    def test_passes_POST_data_to_Form(self, mockMyNewForm):
        event_new(self.t.request)
        mockMyNewForm.assert_called_once_with(data=self.t.request.POST)

Do I somehow have to mock the helper object as well? And how would that be done? Thank you very much!

like image 286
lukas Avatar asked Dec 06 '25 03:12

lukas


1 Answers

Late answer, but ran up against this today. You need to spec the helper for your mock class to the FormHelper so that the "isinstance" call in the crispy templates passes. Easiest way to do this is to create a MagicMock subclass for the crispy form:

class MockCrispyForm(MagicMock):
    helper = MagicMock(spec=FormHelper)
    helper.template = False  # necessary for templates to render
    def is_valid(self):
        return True  # optional if you want form to validate

@patch('myapp.views.MyNewForm', MockCrispyForm())
class MyNewViewUnitTest(TestCase):
    def setUp(self):
        self.t = unittest.TestCase()
        self.t.request = HttpRequest()
        self.t.request.POST['data'] = 'data'
        self.t.request.user = Mock()

    def test_passes_POST_data_to_Form(self):
        event_new(self.t.request)
        myapp.views.MyNewForm.assert_called_once_with(
            data=self.t.request.POST
        )
like image 137
skulegirl Avatar answered Dec 08 '25 16:12

skulegirl