djangounit-testingformset

Django formset unit test


I can't run a unit test with formset.

I try to do a test:

class NewClientTestCase(TestCase):
    
    def setUp(self):
        self.c = Client()

    def test_0_create_individual_with_same_adress(self):
        
        post_data =  {
            'ctype': User.CONTACT_INDIVIDUAL,
            'username': 'dupond.f',        
            'email': 'new@gmail.com', 
            'password': 'pwd', 
            'password2': 'pwd', 
            'civility': User.CIVILITY_MISTER, 
            'first_name': 'François', 
            'last_name': 'DUPOND', 
            'phone': '+33 1 34 12 52 30', 
            'gsm': '+33 6 34 12 52 30', 
            'fax': '+33 1 34 12 52 30', 
            'form-0-address1': '33 avenue Gambetta', 
            'form-0-address2': 'apt 50', 
            'form-0-zip_code': '75020', 
            'form-0-city': 'Paris', 
            'form-0-country': 'FRA', 
            'same_for_billing': True,            
        }
        
        response = self.c.post(reverse('client:full_account'), post_data, follow=True)   

        self.assertRedirects(response, '%s?created=1' % reverse('client:dashboard'))

and I have this error:

ValidationError: [u'ManagementForm data is missing or has been tampered with']

My view :

def full_account(request, url_redirect=''):    
    from forms import NewUserFullForm,  AddressForm,  BaseArticleFormSet
    
    fields_required = []
    fields_notrequired = []
    
    AddressFormSet = formset_factory(AddressForm, extra=2,  formset=BaseArticleFormSet)
    
    if request.method == 'POST':        
        form = NewUserFullForm(request.POST)        
        objforms = AddressFormSet(request.POST)            
       
        if objforms.is_valid() and form.is_valid():            
            user = form.save()            
            address = objforms.forms[0].save()

            
            if url_redirect=='':
                url_redirect = '%s?created=1' % reverse('client:dashboard')
                logon(request, form.instance)            
            return HttpResponseRedirect(url_redirect)
    else:
        form = NewUserFullForm()
        objforms = AddressFormSet()   
    
    return direct_to_template(request, 'clients/full_account.html', {
        'form':form,
        'formset': objforms, 
        'tld_fr':False, 
    })

and my form file :

class BaseArticleFormSet(BaseFormSet):

    def clean(self):        
        
        msg_err = _('Ce champ est obligatoire.')
        non_errors = True
        
        if 'same_for_billing' in self.data and self.data['same_for_billing'] == 'on':
            same_for_billing = True
        else:            
            same_for_billing = False
        
        for i in [0, 1]:
            
            form = self.forms[i]           
            
            for field in form.fields:                                
                name_field = 'form-%d-%s' % (i, field )
                value_field = self.data[name_field].strip()                
                
                if i == 0 and self.forms[0].fields[field].required and value_field =='':                    
                    form.errors[field] = msg_err                    
                    non_errors = False
                    
                elif i == 1 and not same_for_billing and self.forms[1].fields[field].required and value_field =='':
                    form.errors[field] = msg_err                    
                    non_errors = False
        
        return non_errors

class AddressForm(forms.ModelForm):

    class Meta:
        model = Address

    address1 = forms.CharField()
    address2 = forms.CharField(required=False)
    zip_code = forms.CharField()
    city = forms.CharField()
    country = forms.ChoiceField(choices=CountryField.COUNTRIES,  initial='FRA')

Solution

  • Every Django formset comes with a management form that needs to be included in the post. The official docs explain it pretty well. To use it within your unit test, you either need to write it out yourself. (The link I provided shows an example), or call formset.management_form which outputs the data.