lundi 24 décembre 2018

Monkeypatching clean() method in a django Form Class

I use Django 2.1 on python 3.6 with pytest-django 3.4

I like to test the clean() method of a form defined like this :

from django.forms import HiddenInput, ModelForm, ValidationError 
from log.models import Entry 

class EntryForm(ModelForm): 
    class Meta: 
        model = Entry 
        fields = ['user', 'contact', 'title', 'desc'] 
        widgets = { 
            'user': HiddenInput(), 
            'contact': HiddenInput(), 
        } 

    def __init__(self, *args, **kwargs): 
        """ Get back user & contact obj for `self.clean()` """ 
        user = kwargs.pop('user') 
        contact = kwargs.pop('contact') 
        super(EntryForm, self).__init__(*args, **kwargs) 

        self.fields['user'].initial = user 
        self.fields['contact'].initial = contact 

    def clean(self): 
        """ 
        Checks if a entry is added on a contact owned by the connected user 
        """ 
        cleaned_data = super(EntryForm, self).clean()

        if 'user' in self.changed_data or 'contact' in self.changed_data: 
            raise ValidationError("Hidden input changed") 

        if cleaned_data['contact'].user != cleaned_data['user']: 
            raise ValidationError("Not allowed")

Outside tests, in a browser, this work as charm even if I change the values of hidden inputs : the ValidationError is raised.

I think about using monkeypatch but I did not understand how to inject my test conditions in a django class…

I use my feelings to build this test, but I cannot raise the expected ValidationError :

def fake_entry_form__init__():
    self.fields['user'].initial = 'initial user'
    self.fields['contact'].initial = 'initial contact'

def fake_entry_form_unvalid_changed_data():
    return  {
        'user': 'foo user',
        'contact': 'foo contact'
    }

def test_entry_form_clean_unvalid(monkeypatch):
    monkeypatch.setattr('log.forms.EntryForm.__init__', fake_entry_form__init__)

    form = EntryForm
    monkeypatch.setattr('log.forms.EntryForm.changed_data', fake_entry_form_unvalid_changed_data)

    try:
        form.clean
        assert False
    except KeyError:
        assert True

Am I on a good track or completely wrong?

I am new in django, CBV & testing, this is maybe a very obvious case, but I did not find explanation about it.

Aucun commentaire:

Enregistrer un commentaire