djangounit-testing

Django testing a DeleteView


So in a DeleteView, the GET request returns a confirmation page, and a simple POST request with no fields except for the csrf_token actually gets the DeleteView to delete the object, upon which the user gets redirected to the success_url.

How can I test this functionality? In my myclass_confirm_delete.html file, I basically have:

<form action="{% url 'remove_myclass' object.id %}" method="post">
{% csrf_token %}
    <p>Are you sure you want to remove {{ object.name }}?</p>
    <input type="submit" value="Yes" class="btn btn-primary" />
</form>

where {% url 'remove_myclass' object.id %} is the URL of the same exact page. It works in my browser. When I click "Yes," it redirects me to the success page, and the myclass object is removed from the database.

Now I am trying to test this automatically with unit tests. I basically try

response = self.client.get(reverse('remove_myclass', args=(myobject.id,)), follow=True)
self.assertContains(response, 'Are you sure you want to remove') # THIS PART WORKS
self.client.post(reverse('remove_myclass', args=(myobject.id,)), follow=True)
self.assertRedirects(response, reverse('myclass_removed'), status_code=302) # FAILS; status code is 200

If I try print response, I get the same exact response as when I had used the GET request.

It seems like while unit testing, no matter what kind of data I try to send in the POST request, it still gets treated as a GET request...

My class-based view:

class MyclassDelete(DeleteView):
    model = myclass
    success_url = '/myclass-removed/'

Any ideas?


Solution

  • Yeah, this is because you're forgetting to assign the post request to response, so you're checking the same response twice.

    response = self.client.get(reverse('remove_myclass', args=(myobject.id,)), follow=True)
    self.assertContains(response, 'Are you sure you want to remove') # THIS PART WORKS
    
    post_response = self.client.post(reverse('remove_myclass', args=(myobject.id,)), follow=True)
    self.assertRedirects(post_response, reverse('myclass_removed'), status_code=302)
    

    This should do the trick.

    Also, just a tip, trying to assert more than once per unit test is considered bad practice when unit testing. Instead try to break it up so that one test tests the GET and on test tests the POST.

    from django.test import TestCase
    
    class TestDifferentRequestMethods(TestCase):
    
        def test_my_get_request(self):
            response = self.client.get(reverse('remove_myclass', args=(myobject.id,)), follow=True)
            self.assertContains(response, 'Are you sure you want to remove') # THIS PART WORKS
    
        def test_my_post_request(self):
            post_response = self.client.post(reverse('remove_myclass', args=(myobject.id,)), follow=True)
            self.assertRedirects(post_response, reverse('myclass_removed'), status_code=302)
    

    This makes for easier debugging and could save sometimes when stumbling onto these kinds of troubles!

    UPDATE realized that I hadn't completed with a nice class to encompass the tests.