Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 919
wrongusername Avatar asked Apr 15 '13 01:04

wrongusername


1 Answers

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.

like image 178
Henrik Andersson Avatar answered Sep 20 '22 12:09

Henrik Andersson