merryfistmas
merryfistmas

Reputation: 19

Testing Django view

I'm trying to test the following view

def generate_exercise_edl(request, ex_pk, unit_pk, *args, **kwargs):
    ex_instance = Exercises.objects.get(id=ex_pk)
    unit_instance = Units.objects.get(id=unit_pk)
    unit_edl = UnitEdl.objects.filter(unit=unit_instance)
    locations = Locations.objects.all()
    unit_edl = list(unit_edl)
    print(request)
    print(request.POST)
    print(request.user)

    if request.method == "POST":
        for item in unit_edl:
            ExerciseEdl.objects.update_or_create(unit=unit_instance, exercise=ex_instance, equipment=item.equipment,
                                                 quantity=item.quantity, location=Locations.objects.get(location="Okinawa"))
        print(request)
        return redirect('exercise-equipment', ex_pk=ex_pk, unit_pk=unit_pk)
    else:
        messages.error(
            request, f'Failed to add/update the {unit_instance.unit_name} edl for {ex_instance.exercise}.')
    context = {
        'ex_instance': ex_instance,
        'unit_instance': unit_instance,
        'unit_edl': unit_edl,
        'locations': locations,
    }
    return render(request, 'exercise/exercise_edl.html', context)

This is my test code

def test_generate_edl(self):
    unit_edl = UnitEdl.objects.filter(unit=unit.pk)
    for edl in unit_edl:
        ExerciseEdl.objects.update_or_create(
            unit=unit,
            exercise=ex,
            equipment=edl.equipment,
            quantity=edl.quantity,
            location=loc
        )
    response = self.client.post(
        f'/exercise/{ex.pk}/edl/{unit.pk}/convert/')
    ex_edl = ExerciseEdl.objects.all().count()
    self.assertEquals(ex_edl, 2)
    self.assertEqual(response.status_code, 302)

This is the URL for the view

path('exercise/<int:ex_pk>/edl/<int:unit_pk>/convert', views.generate_exercise_edl, name='generate-edl'),

And the part of the template that calls my function

<form action="{% url 'generate-edl' ex_pk=ex_instance.id unit_pk=unit_instance.id %}" method="post">
    {% csrf_token %}
     <input class="btn btn-primary btn-sm mt-2" type="submit" value="Generate EDL">
</form>

My test returns 404, not 302, but the function on the site works, and redirects you. f'/exercise/{ex.pk}/edl/{unit.pk}/convert/' isn't mapped to any template, it's just the url for the function. In the past my tests have returned a status code of 404 when I wrote the post data incorrectly.

print(request.POST) returns:

<QueryDict: {'csrfmiddlewaretoken': ['ZYT0dgMZqqgmCo2OufdI9B0hIJ5k5qPKcxnkReWPZy0iY9McaBO7MHENjYLzH66O']}>

Which makes sense because I'm not sending any post data, just the csrf token.

What I want to know is, am I on the right track with using 'response = self.client.post( f'/exercise/{ex.pk}/edl/{unit.pk}/convert/')'? With my other tests I include the post data in a dictionary along with the URL, but this function doesn't use any, so I just ran a similar function.

Is there a better way to test this? Should I just refactor?

Upvotes: 0

Views: 56

Answers (1)

Dean Elliott
Dean Elliott

Reputation: 1323

You need to use reverse to build your URL rather than hard coding it. Since you hard coded it, it is getting a 404 since the URL the test tried to post to is incorrect.

I don't know the app_name in your URLs file, you will need to add that to the reverse. For example if it was excercise it would be exercise:generate-edl.

from django.urls import reverse


response = self.client.post(reverse(
    '<app_name>:generate-edl',
    kwargs={
        ex_pk: ex.pk,
        unit_pk: unit.pk,
    }
))

Upvotes: 1

Related Questions