Search code examples
djangodjango-modelsdjango-viewshttp-postdjango-testing

How to test views that use post request in django?


here's my view (simplified):

@login_required(login_url='/try_again')
def change_bar(request):
    foo_id = request.POST['fid']
    bar_id = request.POST['bid']
    foo = models.Foo.objects.get(id=foo_id)
    if foo.value > 42:
            bar = models.Bar.objects.get(id=bar_id)
            bar.value = foo.value
            bar.save()
    return other_view(request)

Now I'd like to check if this view works properly (in this simplified model, if Bar instance changes value when it should). How do I go about it?


Solution

  • I'm going to assume you mean automated testing rather than just checking that the post request seems to work. If you do mean the latter, just check by executing the request and checking the values of the relevant Foo and Bar in a shell or in the admin.

    The best way to go about sending POST requests is using a Client. Assuming the name of the view is my_view:

    from django.test import Client
    from django.urls import reverse
    
    c = Client()
    c.post(reverse('my_view'), data={'fid':43, 'bid':20})
    

    But you still need some initial data in the database, and you need to check if the changes you expected to be made got made. This is where you could use a TestCase:

    from django.test import TestCase, Client
    from django.urls import reverse
    
    FooBarTestCase(TestCase):
    
    def setUp(self):
        # create some foo and bar data, using foo.objects.create etc
        # this will be run in between each test - the database is rolled back in between tests
    
    def test_bar_not_changed(self):
        # write a post request which you expect not to change the value 
        # of a bar instance, then check that the values didn't change
        self.assertEqual(bar.value, old_bar.value)
    
    def test_bar_changes(self):
        # write a post request which you expect to change the value of 
        # a bar instance, then assert that it changed as expected
        self.assertEqual(foo.value, bar.value)
    

    A library which I find useful for making setting up some data to execute the tests easier is FactoryBoy. It reduces the boilerplate when it comes to creating new instances of Foo or Bar for testing purposes. Another option is to write fixtures, but I find that less flexible if your models change.

    I'd also recommend this book if you want to know more about testing in python. It's django-oriented, but the principles apply to other frameworks and contexts.

    edit: added advice about factoryboy and link to book