Is there a way to test blog post permissions in PyTest?
I've been trying to make the final test pass. I seem to be getting a 403 error, nothing that I'm not authorized to make a post. Even though I gave the test user authorization to post tests. I don't understand why it's still giving me the 403, even when I coded the authorization of the posts.
Here's the test proper:
@pytest.mark.django_db
def test_add_post_permission(self, test_client, test_user, contributor_group, add_post_permission):
add_post_url = reverse("posts:add_post")
post_list_url = reverse("posts:post_list")
#Test 1: Not logged in - Redirect to login
response_not_logged_in = test_client.get(add_post_url)
assert response_not_logged_in.status_code == 403 # Redirect to login
# Test 2: Logged in
logged_in = test_client.login(email=test_user.email, password="pass123")
assert logged_in
# Test 3: Logged in, but without permission
post_data = {"title": "CBV Post Title", "content": "CBV Post content"}
response_no_perm = test_client.post(add_post_url, post_data)
assert response_no_perm.status_code == 403
assert Post.objects.count() == 0
contributor_group.permissions.add(add_post_permission)
contributor_group.save()
# Assign user to the Contributor Group and give them permission to add posts
test_user.groups.add(contributor_group)
test_user.save()
test_user.get_all_permissions() # Ensure permissions are loaded
# Test 4: Test with permission
response_with_perm = test_client.post(add_post_url, post_data)
print(response_with_perm.status_code)
assert response_with_perm.status_code == 302
assert response_with_perm.url == post_list_url
assert Post.objects.count() == 1
# Test the post
new_post = Post.objects.first()
assert new_post.title == "CBV Post Title"
assert new_post.content == "CBV Post content"
assert new_post.author == test_user
Here's the URL:
urlpatterns = [
re_path(r'^posts/add_post/', AddPostView.as_view(), name="add_post"),
]
Here's the views.py:
class AddPostView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
model = Post
form_class = PostForm
template_name = 'posts/addpost.html'
fields = ['title', 'content']
permission_required = 'posts.add_post'
login_url = 'posts:homepage'
def handle_no_permission(self):
raise PermissionDenied("You do not have permission to add a post.")
def form_valid(self, form):
form.instance.author = self.request.user
messages.success(self.request, "Post created successfully!")
return super().form_valid(form)
If it helps, I also have the form class and the applicable view:
from django import forms
from .models import Post
from django.contrib.auth import get_user_model
class PostForm(forms.ModelForm):
title = forms.CharField(label="Title", max_length=150)
content = forms.CharField(widget=forms.Textarea)
User = get_user_model()
class Meta:
model = Post
fields = ('title', 'content')
{% extends 'base.html' %}
{% block title %} Create a Blog Post! {% endblock %}
{% block content %}
<h1>Create Post</h1>
<br/><br/>
<div class="form-group">
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-secondary">Post</button>
</form>
</div>
{% endblock %}
In addition, is there a logic to test permissions with PyTest? Thanks.
It looks like you want to simulate different types of users (author, random user, anonymous) to confirm they either can or cannot perform certain actions (like update, delete) on a blog post.
You'll need to follow this step-by-step:
Setting up Fixtures for:
a) Author User
b) Other user
c) Anonymous client
d) A sample blog post.
Write Permission Test Cases:
def test_author_can_update_post(author_client, blog_post):
response = author_client.post(f'/blog/{blog_post.id}/edit/', {
'title': 'Updated',
'content': 'Updated content'
})
assert response.status_code == 302 # assuming redirect on success
blog_post.refresh_from_db()
assert blog_post.title == 'Updated'
def test_other_user_cannot_update_post(other_client, blog_post):
response = other_client.post(f'/blog/{blog_post.id}/edit/', {
'title': 'Hacked!',
'content': 'Bad content'
})
assert response.status_code == 403 # Forbidden (or 302 if redirected to login)
def test_anonymous_user_cannot_update_post(client, blog_post):
response = client.post(f'/blog/{blog_post.id}/edit/', {
'title': 'Anonymous edit',
'content': 'Not allowed'
})
assert response.status_code in (302, 403)
Please refer to the following link for updated documentation: RequestFactory Docs