Skip to main content

Module to simplify testing forms in Django framework

Installation

You can simply install it with use of pip:

pip install django-forms-test

Then you’ll import it into your testing script like this:

from django_forms_test import field, cleaned, FormTest

Usage

You will create a subclass of FormTest which is subclass of django.test.TestCase, so you can add tests as you are used to. To the attribute form you assign class of the form you are testing. required_fields should be a list of fields required by your form.

class YourClass(FormTest):
    form = YourForm
    required_fields = ['email', 'message']

Instead of the name of a field you can use a tuple of name and field type. Available field types are URL, TEXT, PASSWORD, USERNAME, EMAIL. Field types serves to additional checking of permitted field value (e.g. a form shouldn’t accept an invalid URL). The TEXT is the default type and has no additional verifications.

class YourClass(FormTest):
    form = YourForm
    required_fields = [('email', field.EMAIL), 'message'] # same as ('message', field.TEXT)

For testing of form’s cleaning methods you can use a decorator cleaned which accepts the input field values as arguments and passes them cleaned to your function.

class YourClass(FormTest):
    form = YourForm

    @cleaned(nick='  Bob ')
    def test_strip_nick(self, nick):
        self.assertEqual(nick, 'Bob')

Example

You code this:

class SaveFormTest(FormTest):
    form = SaveForm
    required_fields = ['title', 'tags', ('url', field.URL)]

    @cleaned(tags='one, two')
    def test_cleaning_tags(self, tags):
        self.assertIsInstance(tags, list)
        self.assertEqual(len(tags), 2)
        self.assertEqual(tags[1], 'two')

    @cleaned(description='')
    def test_cleaning_description(self, description):
        self.assertIsNone(description)

Instead of this:

class SaveFormTest(TestCase):

    data = {
        'title': 'some title',
        'url': 'http://some.url',
        'tags': 'some tags',
    }

    def test_valid_form(self):
        form = SaveForm(self.data)
        self.assertTrue(form.is_valid())

    def test_invalid_url(self):
        my_data = copy(self.data)
        my_data['url'] = 'invalid url'
        form = SaveForm(my_data)

        self.assertFalse(form.is_valid())

    def test_required_fields(self):
        for field in ('title', 'url', 'tags'):
            with self.subTest(field=field):
                my_data = copy(self.data)
                my_data[field] = ''
                form = SaveForm(my_data)

                self.assertFalse(form.is_valid())

    def test_cleaning_tags(self):
        form = SaveForm({'tags': 'one, two'})
        form.is_valid()

        tags = form.cleaned_data['tags']
        self.assertIsInstance(tags, list)
        self.assertEqual(len(tags), 2)
        self.assertEqual(tags[1], 'two')

    def test_cleaning_description(self):
        form = SaveForm({'description': ''})
        form.is_valid()

        description = form.cleaned_data['description']
        self.assertIsNone(description)

And you code this:

class RegisterFormTest(FormTest):
    form = RegisterForm
    required_fields = [
        ('username', field.USERNAME),
        ('email', field.EMAIL),
        ('password', field.PASSWORD),
        ('confirm_password', field.PASSWORD),
    ]

Instead of this:

class RegisterFormTest(TestCase):

    data = {
        'username': 'some_username',
        'email': 'some@email.com',
        'password': 'some password',
        'confirm_password': 'some password',
    }

    def test_valid_form(self):
        form = RegisterForm(self.data)
        self.assertTrue(form.is_valid())

    def test_invalid_username(self):
        my_data = copy(self.data)
        my_data['email'] = 'invalid email'
        form = RegisterForm(my_data)

        self.assertFalse(form.is_valid())

    def test_invalid_email(self):
        my_data = copy(self.data)
        my_data['email'] = 'invalid email'
        form = RegisterForm(my_data)

        self.assertFalse(form.is_valid())

    def test_required_fields(self):
        for field in ('username', 'email', 'password', 'confirm_password'):
            with self.subTest(field=field):
                my_data = copy(self.data)
                my_data[field] = ''
                form = RegisterForm(my_data)

                self.assertFalse(form.is_valid())

    def test_password_safe_input(self):
        form = RegisterForm()
        input_type = form['password'].field.widget.input_type
        self.assertEqual(input_type, 'password')

        input_type = form['confirm_password'].field.widget.input_type
        self.assertEqual(input_type, 'password')

Announcement

I’ve done this just for my personal use, so there are many things that are still missing and I probably won’t implement them until I need them. However feel free to send a pull request if you miss something.

Metadata

Release files for django-forms-test 0.1.post1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-forms-test 0.1.post1
File Size Uploaded Provenance
django-forms-test-0.1.post1.tar.gz 3.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for django-forms-test 0.1.post1
File Interpreter ABI Platform
django_forms_test-0.1.post1-py3-none-any.whl Python 3 none any Details

Total release size: 9.9 kB

Release files / django-forms-test-0.1.post1.tar.gz

Download URL django-forms-test-0.1.post1.tar.gz
Size 3.8 kB
Tags Source
SHA-256 checksum
How to use checksums
ef009558793401f91cfefb34e96647cfa64419b337b666a9d62586b85d043225
BLAKE2b-256 checksum
How to use checksums
5a029d357d84d9751f33209ada808e3f379c557e38bfb2ec625bdeefcbaa91a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release files / django_forms_test-0.1.post1-py3-none-any.whl

Download URL django_forms_test-0.1.post1-py3-none-any.whl
Size 6.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a5599b94caef0b4753c21bd83bdf46df2d14eca5723027d1bd73a61a72a46463
BLAKE2b-256 checksum
How to use checksums
24876a5ba66f70936b2eccc815498f5a395b0a6fc5434a9ce3d6e4f1d5958375
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Security for django-forms-test 0.1.post1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.post1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page