Die Logik lautet:
- Jeder Benutzer kann Rezeptansichten nur einmal erhöhen
- verschiedene Benutzer sollten den Zähler erhöhen
- Redis wird mit MagicMock verspottet
Django View
Code: Select all
# recipehub/apps/recipes/views.py
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, render
from recipehub.apps.recipes.models import Recipe
from recipehub.redis import r
@login_required
def recipe_detail(request, slug):
recipe = get_object_or_404(Recipe, slug=slug, moderation_status="approved")
redis_user_recipe_view_key = f"user:{request.user.id}:recipe:{recipe.id}:view"
redis_all_recipe_view_key = f"recipe:{recipe.id}:views"
if not r.exists(redis_user_recipe_view_key):
r.set(redis_user_recipe_view_key, 1)
r.incr(redis_all_recipe_view_key)
recipe_views = int(r.get(redis_all_recipe_view_key) or 0)
return render(
request,
"recipes/recipe_detail.html",
{
"recipe": recipe,
"views": recipe_views,
},
)
Code: Select all
# recipehub/redis.py
import redis
r = redis.Redis(host="localhost", port=6379, db=0)
Redis-Mock-Fixture**
Code: Select all
import pytest
from unittest.mock import MagicMock
@pytest.fixture()
def mock_redis(mocker):
magic_mock = MagicMock()
mocker.patch("recipehub.redis.r", magic_mock)
return magic_mock
Code: Select all
@pytest.mark.django_db
def test_recipe_detail_first_user_view_increments_counter(client, users_list, mock_redis):
recipe = RecipeFactory.create(slug="fish", moderation_status="approved")
user = users_list["first_simple_user"]
mock_redis.exists.return_value = False
mock_redis.get.return_value = b'1'
mock_redis.incr.return_value = 1
mock_redis.set.return_value = True
client.force_login(user)
response = client.get(
reverse("recipes:recipe-detail", kwargs={"slug": recipe.slug})
)
assertContains(response, '1 views')
Code: Select all
@pytest.mark.django_db
def test_recipe_detail_different_users_increment_counter(client, users_list, mock_redis):
recipe = RecipeFactory.create(slug="fish", moderation_status="approved")
first_user = users_list["first_simple_user"]
second_user = users_list["second_simple_user"]
# First user visit
mock_redis.exists.return_value = False
mock_redis.get.return_value = b'1'
client.force_login(first_user)
first_response = client.get(
reverse("recipes:recipe-detail", kwargs={"slug": recipe.slug})
)
assertContains(first_response, '1 views')
# Second user visit
mock_redis.exists.return_value = False
mock_redis.get.return_value = b'2'
client.force_login(second_user)
second_response = client.get(
reverse("recipes:recipe-detail", kwargs={"slug": recipe.slug})
)
# FAILS: still shows "1 views"
assertContains(second_response, '2 views')
assert mock_redis.incr.call_count == 2
assert mock_redis.set.call_count == 2
zeigt die Antwort immer noch „1 Ansichten“.
Die incr()-Methode wird zweimal aufgerufen, aber der von get() zurückgegebene Wert spiegelt dies nicht wider.
Was ist der richtige Weg, um Redis zu verspotten? pytest-django für Zähler wie incr/get? Reicht MagicMock für diesen Fall nicht aus?
Mobile version