Christopher Chough
Christopher Chough

Reputation: 11

Django unit test will not update BooleanField

I have a situation where I want to have published functionality for articles, and I have it. The problem is that I can't get my unit test to work properly, trying to post True to the published field.

Here's what my tests look like.

class ArticleDetailViewTest(TestCase):

    def setUp(self):
        email = '[email protected]'
        first_name = 'test'
        last_name = 'user'
        password = 'test15146'
        user = User.objects.create_user(email, first_name, last_name, password)
        self.client = Client()
        self.client.login(username='[email protected]', password='test15146')

    def test_can_publish_article_from_POST(self):
        other_article_two = Article.objects.create(name='Test Name One', author=User.objects.get(email='[email protected]'))
        correct_article_two = Article.objects.create(name='Test Name Two', author=User.objects.get(email='[email protected]'))

        response = self.client.post(reverse('publish_article', kwargs={'pk' : correct_article_two.pk}))

        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, f'/articles/{correct_article_two.pk}/')
        self.assertEqual(correct_article_two.published, True)

Here's what my publish article view looks like.

def publish_article(request, pk):
    article = get_object_or_404(models.Article, pk=pk)
    if request.method == "POST":
        article.published = True
        article.save(update_fields=['published'])
        return redirect('article_detail_view', pk=article.pk)
    else:
        raise Http404

Here are my urls.

from django.urls import path

from . import views

urlpatterns = [ 
    path('', views.HomePageView.as_view(), name='home'),
    path('new/', views.ArticleCreateView.as_view(), name='article_new'),
    path('<int:pk>/', views.ArticleDetailView.as_view(), name='article_detail_view'),
    path('<int:pk>/publish/', views.publish_article, name='publish_article'),
    path('<int:pk>/unpublish/', views.unpublish_article, name='unpublish_article'),]

Here are my models.

from django.conf import settings
from django.db import models
from django.urls import reverse
from django import forms

class Article(models.Model):
    name = models.CharField(max_length=255, blank=False)
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE, 
    )
    published = models.BooleanField(default=False)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('article_detail_view', args=[str(self.id)])

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = ['name',]

Lastly, here is the template.

{% extends 'base.html' %}

{% block title %}{{ article.name }}{% endblock %}

{% block content %}

{% if article.author_id == user.pk %}
<div class="row">
    <div class="col-6 col-centered">
        <h2 class="text-center">{{ article.name }}</h2>
        <p class="text-center">by {{ article.author.first_name }} {{ article.author.last_name }}</p>
        {% if article.published %}
            <small class="form-text text-muted mb-1">This article is public.</small>
            <form method="post" action="/articles/{{ article.pk }}/unpublish/">
                {% csrf_token %}
                <input type="submit" name="unpublish" value="Unpublish Article" id="id_unpublish_button" class="btn btn-primary btn-md"/>
            </form>
        {% else %}
            <small class="form-text text-muted mb-1">This article is private.</small>
            <form method="post" action="/articles/{{ article.pk }}/publish/">
                {% csrf_token %}
                <input type="submit" name="publish" value="Publish Article" id="id_publish_button" class="btn btn-primary btn-md"/>
            </form>
        {% endif %}
    </div>
</div>
{% elif article.published %}
<div class="row">
    <div class="col-6 col-centered">
        <h2 class="text-center">{{ article.name }}</h2>
        <p class="text-center">by {{ article.author.first_name }} {{ article.author.last_name }}</p>
    </div>
</div>
{% else %}
<div class="row">
    <div class="col-6 col-centered">
        <p class="text-center">This article is private.</p>
    </div>
</div>
{% endif %}

{% endblock %}

This is the error message I'm getting from my test. The issue seems to be I can post to the URL with self.client.post . Any help would be greatly appreciated.

FAIL: test_can_publish_article_from_POST (articles.tests.ArticleDetailViewTest)

Traceback (most recent call last): File "/Users/christopher.chough/article_directory/articles/tests.py", line 126, in test_can_publish_article_from_POST self.assertEqual(correct_article_two.published, True) AssertionError: False != True


Ran 17 tests in 2.340s

FAILED (failures=1)

Upvotes: 1

Views: 549

Answers (1)

neverwalkaloner
neverwalkaloner

Reputation: 47354

Object in your test method not updated. You can use refresh_from_db method to update it after changes:

def test_can_publish_article_from_POST(self):
    other_article_two = Article.objects.create(name='Test Name One', author=User.objects.get(email='[email protected]'))
    correct_article_two = Article.objects.create(name='Test Name Two', author=User.objects.get(email='[email protected]'))

    response = self.client.post(reverse('publish_article', kwargs={'pk' : correct_article_two.pk}))

    correct_article_two.refresh_from_db() # Add this line

    self.assertEqual(response.status_code, 302)
    self.assertRedirects(response, f'/articles/{correct_article_two.pk}/')
    self.assertEqual(correct_article_two.published, True)

Upvotes: 1

Related Questions