How to test a view in Django

45 views Asked by At

I am learning basics of Django following official tutorial and adding some new features to my application. So I added a view that can nullify all votes of particular question

def nullask(request, question_id):
    question=get_object_or_404(Question, pk = question_id)
    if request.method == "GET":
        return render(request, "polls/nullifyask.html", {"question":question})
    else:
        for i in question.choice_set.all():
            i.votes = 0
            i.save()
        return HttpResponseRedirect(reverse("polls:index"))

So it works fine, but I wanted to practice in writing tests and wanted to write a test that test that votes are really nullified. Here it is

class NullingViewTest(TestCase):
    def test_nulling(self):
        q=create_question(text="Future", days=-1)
        choice=q.choice_set.create(choice_text="1", votes=10)
        response=self.client.post(reverse('polls:nullask', args=(q.id,)))
        self.assertEqual(choice.votes, 0)

It does't work(votes are not changing from 10 to 0 and AssertionError: 10 != 0 appears. I understand why this happens but cannot make it work like I want. What should I do here is nullify ask.html:

<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>Nullyfying of {{question_id}}</title>
  </head>
  <body>
    <form method="post">
      {% csrf_token %}
        <legend><h1>Do you want to nullify votes of question {{question.text}}</h1></legend>
        <input type="submit" name="Yes" value="Yes!">
    </form>
  </body>
</html>

Here are models:

class Question(models.Model):
    text=models.CharField(max_length=200)
    productiondate=models.DateTimeField("date published")

    def was_published_recently(self):
        return self.productiondate >= timezone.now() - datetime.timedelta(days=1) and self.productiondate<timezone.now()
    def __str__(self):
        return self.text
    class Meta:
        permissions=(("can_nullify","User can nullify votes" ),)
class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
    def votesx2(self):
        return self.votes*2
    def __str__(self):
        return self.choice_text

I have tried using question=response.context['question'] in the test but it resulted in an error

1

There are 1 answers

0
schwartz721 On BEST ANSWER

In your test, you need to update the choice Python object to reflect the updated vote count in the database. This can be done by calling refresh_from_db() on the object in your test after you POST to nullask.

class NullingViewTest(TestCase):
    def test_nulling(self):
        q=create_question(text="Future", days=-1)
        choice=q.choice_set.create(choice_text="1", votes=10)
        response=self.client.post(reverse('polls:nullask', args=(q.id,)))
        
        # Update the Python object to reflect changes in the database
        choice.refresh_from_db()
        
        self.assertEqual(choice.votes, 0)