I am working my way through the django tutorial and I reached part 5 - Introducing automated testing. I want to go beyond and write test for the vote method in views.py, but can't realise how to simulate the behaviour of one choice receiving a vote. Is there a way to do this?
models.py:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.question_text
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
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 __str__(self):
return self.choice_text
views.py
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
I've tried multiple stuff in tests.py. This is the latest version - i know choice_vote is currently not what i want, still needs to be filtered:
class QuestionVoteTests(TestCase):
def test_vote(self):
"""
Placeholder for vote method test.
"""
question = create_question(question_text="Question.", days=-5)
self.client.post(
reverse('polls:vote', args=(question.id,))
)
vote(self.client, question.id)
choice_vote = Choice.objects.filter(question_id=question.id).values()
print(choice_vote)
#self.assertEqual(choice_vote, 1)
return 0
I looked at answers on how to test multiple choice, but it only got me this far. Thanks!
Later edit: I run the tests with manage.py command. This is the result:
======================================================================
ERROR: test_vote (polls.tests.QuestionVoteTests)
Placeholder for vote method test.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/gabo/django_projects/mysite/polls/tests.py", line 239, in test_vote
vote(self.client, question.id)
File "/home/gabo/django_projects/mysite/polls/views.py", line 52, in vote
selected_choice = question.choice_set.get(pk=request.POST['choice'])
AttributeError: 'Client' object has no attribute 'POST'
Should also post this part from templates - detail.html
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset>
<legend><h1>{{ question.question_text }}</h1></legend>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}"
value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label>
<br>
{% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>
When I comment out vote(self.client, question.id) in tests.py this is the response:
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.................<QuerySet [{'id': 1, 'question_id': 1, 'choice_text': 'choice 1', 'votes': 0}, {'id': 2, 'question_id': 1, 'choice_text': 'choice 2', 'votes': 0}]>
.
----------------------------------------------------------------------
Ran 18 tests in 0.213s
Looking at the above code for the tests, there are some issues and questions regarding the approach taken. Adding them alongside the code below
def test_vote(self):
"""
Placeholder for vote method test.
"""
question = create_question(question_text="Question.", days=-5)
self.client.post(
reverse('polls:vote', args=(question.id,))
)
vote(self.client, question.id) # Why is the vote call made here?
choice_vote = Choice.objects.filter(question_id=question.id).values()
print(choice_vote) # What is the value of choice vote here?
#self.assertEqual(choice_vote, 1)
return 0. # Do not return from test
Besides this, what do you see in the logs when running the unit tests? Are you using pytest to run the tests or Django's manage.py test command?