From f9b53067f9fec2eea3e587f2c9b275bad9f24087 Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Sun, 11 Feb 2024 13:50:40 +0100 Subject: [PATCH 01/15] refactor: changed ProductViewSet permissions --- Dshop/apps/products_catalogue/api_permissions.py | 5 +++++ Dshop/apps/products_catalogue/api_views.py | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 Dshop/apps/products_catalogue/api_permissions.py diff --git a/Dshop/apps/products_catalogue/api_permissions.py b/Dshop/apps/products_catalogue/api_permissions.py new file mode 100644 index 0000000..dd713d2 --- /dev/null +++ b/Dshop/apps/products_catalogue/api_permissions.py @@ -0,0 +1,5 @@ +from rest_framework.permissions import BasePermission, SAFE_METHODS + +class IsStaffOrReadOnly(BasePermission): + def has_permission(self, request, view): + return (request.method in SAFE_METHODS) or request.user.is_staff == True diff --git a/Dshop/apps/products_catalogue/api_views.py b/Dshop/apps/products_catalogue/api_views.py index c960ba7..9997480 100644 --- a/Dshop/apps/products_catalogue/api_views.py +++ b/Dshop/apps/products_catalogue/api_views.py @@ -4,9 +4,11 @@ from rest_framework.response import Response from rest_framework import status from dj_shop_cart.cart import get_cart_class + from .models import Product from .serializers import CartReadSerializer, ProductSerializer, CartWriteSerializer from .filters import ProductFilter +from .api_permissions import IsStaffOrReadOnly class ProductViewSet(viewsets.ModelViewSet): @@ -14,7 +16,7 @@ class ProductViewSet(viewsets.ModelViewSet): serializer_class = ProductSerializer filter_backends = [DjangoFilterBackend] filterset_class = ProductFilter - + permission_classes = (IsStaffOrReadOnly, ) class CartAPIView(APIView): def post(self, request): From 64896b9d019f6f4006b0b62b88e49254a99684aa Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Sun, 11 Feb 2024 14:35:16 +0100 Subject: [PATCH 02/15] refactor: all client and product fixtures in one place --- .../apps/products_catalogue/tests/conftest.py | 11 ----- .../tests/test_api_persistent_cart.py | 46 +++++++++---------- .../tests/test_api_products.py | 37 ++++----------- Dshop/apps/users/conftest.py | 6 --- Dshop/conftest.py | 34 +++++++++++++- 5 files changed, 64 insertions(+), 70 deletions(-) delete mode 100644 Dshop/apps/products_catalogue/tests/conftest.py diff --git a/Dshop/apps/products_catalogue/tests/conftest.py b/Dshop/apps/products_catalogue/tests/conftest.py deleted file mode 100644 index c8e2609..0000000 --- a/Dshop/apps/products_catalogue/tests/conftest.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.contrib.auth.models import User -import pytest -from rest_framework.test import APIClient - - -@pytest.fixture -def api_client(): - client = APIClient() - user = User.objects.create_user(username='testuser', password='testpassword') - client.force_authenticate(user) - return client \ No newline at end of file diff --git a/Dshop/apps/products_catalogue/tests/test_api_persistent_cart.py b/Dshop/apps/products_catalogue/tests/test_api_persistent_cart.py index b426d5f..3219e85 100644 --- a/Dshop/apps/products_catalogue/tests/test_api_persistent_cart.py +++ b/Dshop/apps/products_catalogue/tests/test_api_persistent_cart.py @@ -33,21 +33,21 @@ def assert_data_empty(data): @pytest.mark.django_db -def test_get_cart_empty(api_client): - response = api_client.get(reverse("api_cart")) +def test_get_cart_empty(api_client_authed): + response = api_client_authed.get(reverse("api_cart")) assert response.status_code == status.HTTP_200_OK assert_data_empty(response.data) @pytest.mark.django_db -def test_add(api_client, tv_product): +def test_add(api_client_authed, tv_product): data = { 'items': [ {'product_pk': tv_product.pk, 'quantity': 10} ] } - response = api_client.post(reverse("api_cart"), data) + response = api_client_authed.post(reverse("api_cart"), data) assert_products_data(response.data, [tv_product], [10]) assert response.status_code == status.HTTP_201_CREATED - response = api_client.get(reverse("api_cart")) + response = api_client_authed.get(reverse("api_cart")) assert response.status_code == status.HTTP_200_OK assert_products_data(response.data, [tv_product], [10]) @@ -72,7 +72,7 @@ def test_add_relogin_get(tv_product): @pytest.mark.django_db -def test_add_ten_and_get(api_client, ten_tv_products): +def test_add_ten_and_get(api_client_authed, ten_tv_products): quantities = [1, 1, 6, 8, 3, 4, 2, 26, 1, 10] data = { @@ -81,16 +81,16 @@ def test_add_ten_and_get(api_client, ten_tv_products): for product, quantity in zip(ten_tv_products, quantities) ] } - response = api_client.post(reverse("api_cart"), data) + response = api_client_authed.post(reverse("api_cart"), data) assert response.status_code == status.HTTP_201_CREATED assert_products_data(response.data, ten_tv_products, quantities) - response = api_client.get(reverse("api_cart")) + response = api_client_authed.get(reverse("api_cart")) assert response.status_code == status.HTTP_200_OK assert_products_data(response.data, ten_tv_products, quantities) @pytest.mark.django_db -def test_add_ten_replace_with_one(api_client, ten_tv_products, tv_product): +def test_add_ten_replace_with_one(api_client_authed, ten_tv_products, tv_product): quantities = [11, 1, 3, 8, 4, 5, 6, 7, 1, 10] data = { 'items': [ @@ -98,7 +98,7 @@ def test_add_ten_replace_with_one(api_client, ten_tv_products, tv_product): for product, quantity in zip(ten_tv_products, quantities) ] } - response = api_client.post(reverse("api_cart"), data) + response = api_client_authed.post(reverse("api_cart"), data) assert response.status_code == status.HTTP_201_CREATED data = { @@ -106,16 +106,16 @@ def test_add_ten_replace_with_one(api_client, ten_tv_products, tv_product): {'product_pk': tv_product.pk, 'quantity': 666} ] } - response = api_client.post(reverse("api_cart"), data) + response = api_client_authed.post(reverse("api_cart"), data) assert response.status_code == status.HTTP_201_CREATED assert_products_data(response.data, [tv_product], [666]) - response = api_client.get(reverse("api_cart")) + response = api_client_authed.get(reverse("api_cart")) assert response.status_code == status.HTTP_200_OK assert_products_data(response.data, [tv_product], [666]) @pytest.mark.django_db -def test_delete_ten(api_client, ten_tv_products): +def test_delete_ten(api_client_authed, ten_tv_products): quantities = [1, 1, 6, 8, 3, 4, 2, 26, 1, 10] data = { 'items': [ @@ -123,30 +123,30 @@ def test_delete_ten(api_client, ten_tv_products): for product, quantity in zip(ten_tv_products, quantities) ] } - response = api_client.post(reverse("api_cart"), data) + response = api_client_authed.post(reverse("api_cart"), data) assert response.status_code == status.HTTP_201_CREATED - response = api_client.post(reverse("api_cart"), {}) + response = api_client_authed.post(reverse("api_cart"), {}) assert response.status_code == status.HTTP_201_CREATED assert_data_empty(response.data) - response = api_client.get(reverse("api_cart")) + response = api_client_authed.get(reverse("api_cart")) assert_data_empty(response.data) @pytest.mark.django_db -def test_get_non_unique_pks(api_client, tv_product): +def test_get_non_unique_pks(api_client_authed, tv_product): data = { 'items':[ {'product_pk': tv_product.pk, 'quantity': 2}, {'product_pk': tv_product.pk, 'quantity': 3} ] } - response = api_client.post(reverse("api_cart"), data) + response = api_client_authed.post(reverse("api_cart"), data) assert str(response.data['items'][0]) == "product_pk must be unique within items." assert response.status_code == status.HTTP_400_BAD_REQUEST @pytest.mark.django_db -def test_get_non_existing_pks(api_client, tv_product): +def test_get_non_existing_pks(api_client_authed, tv_product): NON_EXISTING_ID = 999999 data = { 'items':[ @@ -154,20 +154,20 @@ def test_get_non_existing_pks(api_client, tv_product): {'product_pk': NON_EXISTING_ID, 'quantity': 3} ] } - response = api_client.post(reverse("api_cart"), data) + response = api_client_authed.post(reverse("api_cart"), data) assert response.status_code == status.HTTP_404_NOT_FOUND - response = api_client.get(reverse("api_cart")) + response = api_client_authed.get(reverse("api_cart")) assert_data_empty(response.data) @pytest.mark.django_db -def test_get_zero_quantities(api_client, tv_product): +def test_get_zero_quantities(api_client_authed, tv_product): data = { 'items':[ {'product_pk': tv_product.pk, 'quantity': 0} ] } - response = api_client.post(reverse("api_cart"), data) + response = api_client_authed.post(reverse("api_cart"), data) error_str = str(response.data['items'][0]['quantity'][0]) assert response.status_code == status.HTTP_400_BAD_REQUEST assert error_str == 'Ensure this value is greater than or equal to 1.' diff --git a/Dshop/apps/products_catalogue/tests/test_api_products.py b/Dshop/apps/products_catalogue/tests/test_api_products.py index ec4ae55..1173891 100644 --- a/Dshop/apps/products_catalogue/tests/test_api_products.py +++ b/Dshop/apps/products_catalogue/tests/test_api_products.py @@ -1,13 +1,7 @@ import pytest from django.urls import reverse +from rest_framework.test import APIClient from apps.products_catalogue.models import Category, Product -# pylama:ignore=W0404, W0611 -from apps.users.conftest import api_client, login_url, login_data, user_instance, user_instance_token - - -@pytest.fixture -def create_category(): - return Category.objects.create(name='Test Category', is_active=True) @pytest.fixture @@ -36,12 +30,6 @@ def create_inactive_product(): ) -@pytest.fixture -def authenticated_api_client(api_client, user_instance_token): - api_client.credentials(HTTP_AUTHORIZATION=f'Token {user_instance_token.key}') - return api_client - - def assert_active_object(data): assert data['category'] is not None @@ -59,9 +47,9 @@ def assert_active_object(data): @pytest.mark.django_db -def test_access_protected_resource(authenticated_api_client, create_active_product, create_inactive_product): +def test_access_protected_resource(api_client_authed, create_active_product, create_inactive_product): url = reverse('products-api-list') - response = authenticated_api_client.get(url) + response = api_client_authed.get(url) assert response.status_code == 200 results = response.data.get('results', []) @@ -72,17 +60,10 @@ def test_access_protected_resource(authenticated_api_client, create_active_produ assert_active_object(product_data) -def test_access_protected_resource_without_authentication(api_client): - url = reverse('products-api-list') - response = api_client.get(url) - - assert response.status_code == 401 - - @pytest.mark.django_db -def test_product_detail(authenticated_api_client, create_active_product): +def test_product_detail(api_client_authed, create_active_product): url = reverse('products-api-detail', kwargs={'pk': create_active_product.id}) - response = authenticated_api_client.get(url) + response = api_client_authed.get(url) assert response.status_code == 200 assert response.data['id'] == create_active_product.id @@ -93,7 +74,7 @@ def test_product_detail(authenticated_api_client, create_active_product): @pytest.mark.django_db -def test_create_product(authenticated_api_client, create_category): +def test_create_product(api_client_authed, create_category): url = reverse('products-api-list') data = { 'category': create_category.id, @@ -102,7 +83,7 @@ def test_create_product(authenticated_api_client, create_category): 'short_description': 'Test short description', 'full_description': 'Test full description', } - response = authenticated_api_client.post(url, data, format='json') + response = api_client_authed.post(url, data, format='json') assert response.status_code == 201 assert response.data['name'] == "Test Product" @@ -110,10 +91,10 @@ def test_create_product(authenticated_api_client, create_category): @pytest.mark.django_db -def test_update_product(authenticated_api_client, create_active_product): +def test_update_product(api_client_authed, create_active_product): url = reverse('products-api-detail', kwargs={'pk': create_active_product.id}) data = {'name': 'Updated product name'} - response = authenticated_api_client.patch(url, data, format='json') + response = api_client_authed.patch(url, data, format='json') assert response.status_code == 200 assert response.data['name'] == "Updated product name" diff --git a/Dshop/apps/users/conftest.py b/Dshop/apps/users/conftest.py index fe58b0a..10dea54 100644 --- a/Dshop/apps/users/conftest.py +++ b/Dshop/apps/users/conftest.py @@ -6,12 +6,6 @@ User = get_user_model() - -@pytest.fixture -def api_client(): - return APIClient() - - @pytest.fixture def login_url(): return reverse('api-login') diff --git a/Dshop/conftest.py b/Dshop/conftest.py index 57ddb41..cd98d03 100644 --- a/Dshop/conftest.py +++ b/Dshop/conftest.py @@ -3,13 +3,43 @@ from django.urls import reverse from pytest import fixture from apps.products_catalogue.models import Category, Product -from apps.users.models import CustomUser +from django.contrib.auth import get_user_model +from rest_framework.test import APIClient -User = CustomUser +User = get_user_model() Cart = get_cart_class() +@pytest.fixture +def api_client(): + return APIClient() + +@pytest.fixture +def api_client_authed(): + client = APIClient() + user = User.objects.create_user(username='testuser', password='testpassword') + client.force_authenticate(user) + return client + +@pytest.fixture +def api_client_staff(): + client = APIClient() + staff_user = User.objects.create_user(username='staffuser', is_staff=True, password="staffsword") + client.force_authenticate(staff_user) + return client + +@pytest.fixture +def api_client_admin(): + client = APIClient() + admin = User.objects.create_user(username='admin', is_staff=True, is_admin=True, password='@dmin123') + client.force_authenticate(admin) + return client + +@pytest.fixture +def create_category(): + return Category.objects.create(name='Test Category', is_active=True) + @fixture @pytest.mark.django_db def tv_product(): From 69e9607b18c2d00a2fdd4d393064296f8999a724 Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Sun, 11 Feb 2024 19:15:13 +0100 Subject: [PATCH 03/15] refactor: Products - helpers, fixtures, some tests --- Dshop/Dshop/settings.py | 2 +- .../tests/test_api_products.py | 106 ++++++++---------- Dshop/conftest.py | 18 ++- 3 files changed, 66 insertions(+), 60 deletions(-) diff --git a/Dshop/Dshop/settings.py b/Dshop/Dshop/settings.py index 22338df..39ea34b 100644 --- a/Dshop/Dshop/settings.py +++ b/Dshop/Dshop/settings.py @@ -213,7 +213,7 @@ }, "TEST_REQUEST_DEFAULT_FORMAT": "json", "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", - "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination", + "DEFAULT_PAGINATION_CLASS": 'rest_framework.pagination.PageNumberPagination', "PAGE_SIZE": 25, "DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"] diff --git a/Dshop/apps/products_catalogue/tests/test_api_products.py b/Dshop/apps/products_catalogue/tests/test_api_products.py index 1173891..5c3e4ba 100644 --- a/Dshop/apps/products_catalogue/tests/test_api_products.py +++ b/Dshop/apps/products_catalogue/tests/test_api_products.py @@ -1,45 +1,16 @@ +from rest_framework.test import APIClient import pytest from django.urls import reverse -from rest_framework.test import APIClient -from apps.products_catalogue.models import Category, Product - - -@pytest.fixture -def create_active_product(): - category = Category.objects.create(name='Test Category', is_active=True) - return Product.objects.create( - name="main product", - category=category, - price=11, - short_description="short desc", - full_description="full_description", - is_active=True - ) - - -@pytest.fixture -def create_inactive_product(): - category = Category.objects.create(name='Test Category 2', is_active=True) - return Product.objects.create( - name="main product inactive", - category=category, - price=150, - short_description="short desc inactive", - full_description="full_description inactive", - is_active=False - ) def assert_active_object(data): - assert data['category'] is not None - fields_values = { "id": 1, "category": 1, - "name": "main product", - "price": "11.00", - "short_description": "short desc", - "full_description": "full_description", + "name": "TV AMOLED", + "price": "3999.00", + "short_description": 'Test short description', + "full_description": 'Test full description', "parent_product": None, } for key, value in data.items(): @@ -47,35 +18,28 @@ def assert_active_object(data): @pytest.mark.django_db -def test_access_protected_resource(api_client_authed, create_active_product, create_inactive_product): +def test_get_list_one(api_client, tv_product, inactive_product): url = reverse('products-api-list') - response = api_client_authed.get(url) + response = api_client.get(url) assert response.status_code == 200 - results = response.data.get('results', []) assert len(results) == 1 - product_data = results[0] - + assert response.data['count'] == 1 + assert response.data['previous'] is None + assert response.data['next'] is None assert_active_object(product_data) @pytest.mark.django_db -def test_product_detail(api_client_authed, create_active_product): - url = reverse('products-api-detail', kwargs={'pk': create_active_product.id}) - response = api_client_authed.get(url) - - assert response.status_code == 200 - assert response.data['id'] == create_active_product.id - assert response.data['name'] == "main product" - assert response.data['price'] == "11.00" - assert response.data['short_description'] == "short desc" - assert response.data['full_description'] == "full_description" +def test_product_detail_404(): + url = reverse('products-api-detail', kwargs={'pk': 6669}) + response = APIClient().get(url) + assert response.status_code == 404 @pytest.mark.django_db -def test_create_product(api_client_authed, create_category): - url = reverse('products-api-list') +def test_create_product(api_client_staff, create_category): data = { 'category': create_category.id, 'name': 'Test Product', @@ -83,7 +47,8 @@ def test_create_product(api_client_authed, create_category): 'short_description': 'Test short description', 'full_description': 'Test full description', } - response = api_client_authed.post(url, data, format='json') + url = reverse('products-api-list') + response = api_client_staff.post(url, data, format='json') assert response.status_code == 201 assert response.data['name'] == "Test Product" @@ -91,11 +56,38 @@ def test_create_product(api_client_authed, create_category): @pytest.mark.django_db -def test_update_product(api_client_authed, create_active_product): - url = reverse('products-api-detail', kwargs={'pk': create_active_product.id}) +def test_update_product(api_client_staff, tv_product): + url = reverse('products-api-detail', kwargs={'pk': tv_product.id}) data = {'name': 'Updated product name'} - response = api_client_authed.patch(url, data, format='json') + response = api_client_staff.patch(url, data, format='json') + assert response.status_code == 200 + tv_product.refresh_from_db() + assert tv_product.name == "Updated product name" + +@pytest.fixture(autouse=True) +def set_test_pagination_size(settings): + settings.REST_FRAMEWORK['PAGE_SIZE'] = 5 + + +@pytest.mark.django_db +def test_product_list_empty(): + response = APIClient().get(reverse("products-api-list")) + print(response.data) + assert response.status_code == 200 + assert response.data['results'] == [] + assert response.data['count'] == 0 + assert response.data['previous'] is None + assert response.data['next'] is None + +@pytest.mark.django_db +def test_product_detail(tv_product): + url = reverse('products-api-detail', kwargs={'pk': tv_product.id}) + response = APIClient().get(url) assert response.status_code == 200 - assert response.data['name'] == "Updated product name" - assert response.data['short_description'] == "short desc" + + +@pytest.mark.django_db +def test_product_list_pagination_ten_products_page_too_far(tv_product): + response = APIClient().get(f"{reverse('products-api-list')}?page=100") + assert response.status_code == 404 \ No newline at end of file diff --git a/Dshop/conftest.py b/Dshop/conftest.py index cd98d03..25a3399 100644 --- a/Dshop/conftest.py +++ b/Dshop/conftest.py @@ -50,12 +50,26 @@ def tv_product(): product = Product.objects.create( name='TV AMOLED', price=3999.00, - full_description='Description 1', - category=category + full_description='Test full description', + short_description='Test short description', + category=category, ) return product +@pytest.fixture +def inactive_product(): + category = Category.objects.create(name='Test Category 2', is_active=True) + return Product.objects.create( + name="main product inactive", + category=category, + price=150, + short_description="short desc inactive", + full_description="full_description inactive", + is_active=False + ) + + @fixture @pytest.mark.django_db def ten_tv_products(): From ba8c329be774dff501d26b002abbc9333c3e5bf8 Mon Sep 17 00:00:00 2001 From: Krzysztof Knop Date: Thu, 15 Feb 2024 19:16:12 +0100 Subject: [PATCH 04/15] refactor: changed ProductViewSet ModelViewSet to ReadOnlyModelViewSet --- Dshop/apps/products_catalogue/api_views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dshop/apps/products_catalogue/api_views.py b/Dshop/apps/products_catalogue/api_views.py index 9997480..b8e07b5 100644 --- a/Dshop/apps/products_catalogue/api_views.py +++ b/Dshop/apps/products_catalogue/api_views.py @@ -11,7 +11,7 @@ from .api_permissions import IsStaffOrReadOnly -class ProductViewSet(viewsets.ModelViewSet): +class ProductViewSet(viewsets.ReadOnlyModelViewSet): queryset = Product.objects.filter(is_active=True, parent_product=None) serializer_class = ProductSerializer filter_backends = [DjangoFilterBackend] From 34bd688ec681f9740ffe666ec66d1a7ab52e20dd Mon Sep 17 00:00:00 2001 From: Krzysztof Knop Date: Thu, 15 Feb 2024 19:17:48 +0100 Subject: [PATCH 05/15] refactor: changed ProductViewSet permissions from own permission class to AllowAny --- Dshop/apps/products_catalogue/api_views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dshop/apps/products_catalogue/api_views.py b/Dshop/apps/products_catalogue/api_views.py index b8e07b5..b3f59f2 100644 --- a/Dshop/apps/products_catalogue/api_views.py +++ b/Dshop/apps/products_catalogue/api_views.py @@ -4,11 +4,11 @@ from rest_framework.response import Response from rest_framework import status from dj_shop_cart.cart import get_cart_class +from rest_framework.permissions import AllowAny from .models import Product from .serializers import CartReadSerializer, ProductSerializer, CartWriteSerializer from .filters import ProductFilter -from .api_permissions import IsStaffOrReadOnly class ProductViewSet(viewsets.ReadOnlyModelViewSet): @@ -16,7 +16,7 @@ class ProductViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = ProductSerializer filter_backends = [DjangoFilterBackend] filterset_class = ProductFilter - permission_classes = (IsStaffOrReadOnly, ) + permission_classes = (AllowAny, ) class CartAPIView(APIView): def post(self, request): From f617a1d0027e7e023ead4a9c2f23f5a82c900a0c Mon Sep 17 00:00:00 2001 From: Krzysztof Knop Date: Thu, 15 Feb 2024 19:18:30 +0100 Subject: [PATCH 06/15] refactor: deleted unnecessary tests for api products --- .../tests/test_api_products.py | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/Dshop/apps/products_catalogue/tests/test_api_products.py b/Dshop/apps/products_catalogue/tests/test_api_products.py index 5c3e4ba..1b013c8 100644 --- a/Dshop/apps/products_catalogue/tests/test_api_products.py +++ b/Dshop/apps/products_catalogue/tests/test_api_products.py @@ -38,33 +38,6 @@ def test_product_detail_404(): assert response.status_code == 404 -@pytest.mark.django_db -def test_create_product(api_client_staff, create_category): - data = { - 'category': create_category.id, - 'name': 'Test Product', - 'price': '19.99', - 'short_description': 'Test short description', - 'full_description': 'Test full description', - } - url = reverse('products-api-list') - response = api_client_staff.post(url, data, format='json') - - assert response.status_code == 201 - assert response.data['name'] == "Test Product" - assert response.data['price'] == "19.99" - - -@pytest.mark.django_db -def test_update_product(api_client_staff, tv_product): - url = reverse('products-api-detail', kwargs={'pk': tv_product.id}) - data = {'name': 'Updated product name'} - response = api_client_staff.patch(url, data, format='json') - assert response.status_code == 200 - tv_product.refresh_from_db() - assert tv_product.name == "Updated product name" - - @pytest.fixture(autouse=True) def set_test_pagination_size(settings): settings.REST_FRAMEWORK['PAGE_SIZE'] = 5 From 6f7ee24ea99337dbf68dbb832a411eaac420e059 Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Sat, 17 Feb 2024 15:13:57 +0100 Subject: [PATCH 07/15] test: two pagination tests added - to be fixed --- .../tests/test_api_products.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Dshop/apps/products_catalogue/tests/test_api_products.py b/Dshop/apps/products_catalogue/tests/test_api_products.py index 1b013c8..244db1e 100644 --- a/Dshop/apps/products_catalogue/tests/test_api_products.py +++ b/Dshop/apps/products_catalogue/tests/test_api_products.py @@ -63,4 +63,21 @@ def test_product_detail(tv_product): @pytest.mark.django_db def test_product_list_pagination_ten_products_page_too_far(tv_product): response = APIClient().get(f"{reverse('products-api-list')}?page=100") - assert response.status_code == 404 \ No newline at end of file + assert response.status_code == 404 + +@pytest.mark.django_db +def test_product_list_pagination_ten_products_page_1(ten_tv_products): + response = APIClient().get(reverse("products-api-list")) + assert len(response.data['results']) == 5 + assert response.data['count'] == 10 + assert response.data['next'] == "http://testserver/api/products/?page=2" + assert response.data['previous'] is None + + +@pytest.mark.django_db +def test_product_list_pagination_ten_products_page_2(ten_tv_products): + response = APIClient().get(f"{reverse('products-api-list')}?page=2") + assert len(response.data['results']) == 5 + assert response.data['count'] == 10 + assert response.data['next'] is None + assert response.data['previous'] == "http://testserver/api/products/" \ No newline at end of file From b21f0a7089ddb56aa999816793d671fdafa87c01 Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Sat, 17 Feb 2024 16:27:31 +0100 Subject: [PATCH 08/15] test: added product generating fixture --- Dshop/conftest.py | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/Dshop/conftest.py b/Dshop/conftest.py index 25a3399..b958760 100644 --- a/Dshop/conftest.py +++ b/Dshop/conftest.py @@ -91,6 +91,60 @@ def ten_tv_products(): ] return [Product.objects.create(**data) for data in tv_data] +@fixture +@pytest.mark.django_db +def forty_three_tv_products(): + category, _ = Category.objects.get_or_create( + name='TVs', + is_active=True + ) + tv_data = [ + {'name': 'LED TV 22', 'price': 349.00, 'full_description': '22-inch LED TV for small spaces.', 'category': category}, + {'name': 'Smart TV 50', 'price': 1499.00, 'full_description': '50-inch Smart TV with voice control.', 'category': category}, + {'name': 'Ultra Slim TV 32', 'price': 699.00, 'full_description': '32-inch Ultra Slim TV for a sleek look.', 'category': category}, + {'name': 'Portable TV 15', 'price': 199.00, 'full_description': '15-inch Portable TV for on-the-go entertainment.', 'category': category}, + {'name': 'HD Ready TV 28', 'price': 449.00, 'full_description': '28-inch HD Ready TV for clear visuals.', 'category': category}, + {'name': 'Smart LED TV 65', 'price': 2499.00, 'full_description': '65-inch Smart LED TV with streaming apps.', 'category': category}, + {'name': 'Curved OLED TV 55', 'price': 1899.00, 'full_description': '55-inch Curved OLED TV for immersive viewing.', 'category': category}, + {'name': '4K QLED TV 85', 'price': 3999.00, 'full_description': '85-inch 4K QLED TV for a cinematic experience.', 'category': category}, + {'name': 'Portable Gaming TV 20', 'price': 299.00, 'full_description': '20-inch Portable Gaming TV for gaming on the move.', 'category': category}, + {'name': 'Outdoor Smart TV 65', 'price': 2799.00, 'full_description': '65-inch Outdoor Smart TV for outdoor entertainment.', 'category': category}, + {'name': 'Ultra HD Smart TV 60', 'price': 2199.00, 'full_description': '60-inch Ultra HD Smart TV with advanced features.', 'category': category}, + {'name': 'Portable LED TV 18', 'price': 179.00, 'full_description': '18-inch Portable LED TV for convenient viewing.', 'category': category}, + {'name': 'QLED Gaming TV 40', 'price': 1299.00, 'full_description': '40-inch QLED Gaming TV with low input lag.', 'category': category}, + {'name': 'Android Smart TV 55', 'price': 1699.00, 'full_description': '55-inch Android Smart TV for a connected experience.', 'category': category}, + {'name': 'Curved 4K OLED TV 70', 'price': 2899.00, 'full_description': '70-inch Curved 4K OLED TV for stunning visuals.', 'category': category}, + {'name': 'HD Outdoor TV 32', 'price': 599.00, 'full_description': '32-inch HD Outdoor TV for outdoor entertainment.', 'category': category}, + {'name': 'Slim LED TV 26', 'price': 399.00, 'full_description': '26-inch Slim LED TV for a space-saving design.', 'category': category}, + {'name': 'Smart QLED TV 50', 'price': 1599.00, 'full_description': '50-inch Smart QLED TV with voice recognition.', 'category': category}, + {'name': 'Portable HD TV 14', 'price': 149.00, 'full_description': '14-inch Portable HD TV for on-the-go use.', 'category': category}, + {'name': 'Gaming Monitor TV 27', 'price': 699.00, 'full_description': '27-inch Gaming Monitor TV for console gaming.', 'category': category}, + {"name": "Ultra HD Smart TV 61", "price": 2299.00, "full_description": "61-inch Ultra HD Smart TV with advanced features.", "category": category}, + {"name": "Portable LED TV 19", "price": 189.00, "full_description": "19-inch Portable LED TV for convenient viewing.", "category": category}, + {"name": "QLED Gaming TV 41", "price": 1399.00, "full_description": "41-inch QLED Gaming TV with low input lag.", "category": category}, + {"name": "Android Smart TV 56", "price": 1799.00, "full_description": "56-inch Android Smart TV for a connected experience.", "category": category}, + {"name": "Curved 4K OLED TV 71", "price": 2999.00, "full_description": "71-inch Curved 4K OLED TV for stunning visuals.", "category": category}, + {"name": "HD Outdoor TV 33", "price": 699.00, "full_description": "33-inch HD Outdoor TV for outdoor entertainment.", "category": category}, + {"name": "Slim LED TV 27", "price": 499.00, "full_description": "27-inch Slim LED TV for a space-saving design.", "category": category}, + {"name": "Smart QLED TV 51", "price": 1699.00, "full_description": "51-inch Smart QLED TV with voice recognition.", "category": category}, + {"name": "Portable HD TV 15", "price": 159.00, "full_description": "15-inch Portable HD TV for on-the-go use.", "category": category}, + {"name": "Gaming Monitor TV 28", "price": 799.00, "full_description": "28-inch Gaming Monitor TV for console gaming.", "category": category}, + {"name": "Ultra HD Smart TV 62", "price": 2399.00, "full_description": "62-inch Ultra HD Smart TV with advanced features.", "category": category}, + {"name": "Portable LED TV 20", "price": 199.00, "full_description": "20-inch Portable LED TV for convenient viewing.", "category": category}, + {"name": "QLED Gaming TV 42", "price": 1499.00, "full_description": "42-inch QLED Gaming TV with low input lag.", "category": category}, + {"name": "Android Smart TV 57", "price": 1899.00, "full_description": "57-inch Android Smart TV for a connected experience.", "category": category}, + {"name": "Curved 4K OLED TV 72", "price": 3099.00, "full_description": "72-inch Curved 4K OLED TV for stunning visuals.", "category": category}, + {"name": "HD Outdoor TV 34", "price": 799.00, "full_description": "34-inch HD Outdoor TV for outdoor entertainment.", "category": category}, + {"name": "Slim LED TV 28", "price": 549.00, "full_description": "28-inch Slim LED TV for a space-saving design.", "category": category}, + {"name": "Smart QLED TV 52", "price": 1799.00, "full_description": "52-inch Smart QLED TV with voice recognition.", "category": category}, + {"name": "Portable HD TV 16", "price": 169.00, "full_description": "16-inch Portable HD TV for on-the-go use.", "category": category}, + {"name": "Gaming Monitor TV 29", "price": 899.00, "full_description": "29-inch Gaming Monitor TV for console gaming.", "category": category}, + {"name": "Ultra HD Smart TV 63", "price": 2499.00, "full_description": "63-inch Ultra HD Smart TV with advanced features.", "category": category}, + {"name": "Portable LED TV 21", "price": 209.00, "full_description": "21-inch Portable LED TV for convenient viewing.", "category": category}, + {"name": "4K UHD OLED TV 85", "price": 4999.00, "full_description": "85-inch 4K UHD OLED TV for breathtaking visuals.", "category": category} + ] + return [Product.objects.create(**data) for data in tv_data] + @fixture @pytest.mark.django_db From 2fcf1075c1c93f6399c646f48b833f0e4d6ac8f9 Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Sat, 17 Feb 2024 17:36:47 +0100 Subject: [PATCH 09/15] test: added pagination tests, added deletion test --- .../tests/test_api_products.py | 78 +++++++++++++++---- 1 file changed, 64 insertions(+), 14 deletions(-) diff --git a/Dshop/apps/products_catalogue/tests/test_api_products.py b/Dshop/apps/products_catalogue/tests/test_api_products.py index 244db1e..3407826 100644 --- a/Dshop/apps/products_catalogue/tests/test_api_products.py +++ b/Dshop/apps/products_catalogue/tests/test_api_products.py @@ -18,9 +18,9 @@ def assert_active_object(data): @pytest.mark.django_db -def test_get_list_one(api_client, tv_product, inactive_product): +def test_get_list_one(set_test_pagination_size, tv_product, inactive_product): url = reverse('products-api-list') - response = api_client.get(url) + response = APIClient().get(url) assert response.status_code == 200 results = response.data.get('results', []) assert len(results) == 1 @@ -38,21 +38,29 @@ def test_product_detail_404(): assert response.status_code == 404 -@pytest.fixture(autouse=True) +@pytest.fixture def set_test_pagination_size(settings): - settings.REST_FRAMEWORK['PAGE_SIZE'] = 5 - + # alternative settings.REST_FRAMEWORK['PAGE_SIZE'] = 5 + original = settings.REST_FRAMEWORK + import copy + rest = copy.deepcopy(settings.REST_FRAMEWORK) + rest['PAGE_SIZE'] = 5 + settings.REST_FRAMEWORK = rest + yield + settings.REST_FRAMEWORK = original + @pytest.mark.django_db -def test_product_list_empty(): +def test_product_list_empty(set_test_pagination_size): response = APIClient().get(reverse("products-api-list")) - print(response.data) assert response.status_code == 200 assert response.data['results'] == [] assert response.data['count'] == 0 assert response.data['previous'] is None assert response.data['next'] is None + + @pytest.mark.django_db def test_product_detail(tv_product): url = reverse('products-api-detail', kwargs={'pk': tv_product.id}) @@ -60,24 +68,66 @@ def test_product_detail(tv_product): assert response.status_code == 200 + @pytest.mark.django_db -def test_product_list_pagination_ten_products_page_too_far(tv_product): +def test_product_list_pagination_ten_products_page_too_far(set_test_pagination_size, tv_product): response = APIClient().get(f"{reverse('products-api-list')}?page=100") assert response.status_code == 404 + +@pytest.mark.parametrize("page_suffix", ["", "?page=1"]) @pytest.mark.django_db -def test_product_list_pagination_ten_products_page_1(ten_tv_products): - response = APIClient().get(reverse("products-api-list")) - assert len(response.data['results']) == 5 +def test_product_list_pagination_ten_products_page_1(set_test_pagination_size, page_suffix, ten_tv_products):#, ten_tv_products): + response = APIClient().get(reverse("products-api-list") + page_suffix) + results = response.data['results'] + assert len(results) == 5 + assert results[0]['id'] == ten_tv_products[0].id + assert results[4]['id'] == ten_tv_products[4].id assert response.data['count'] == 10 assert response.data['next'] == "http://testserver/api/products/?page=2" assert response.data['previous'] is None @pytest.mark.django_db -def test_product_list_pagination_ten_products_page_2(ten_tv_products): +def test_product_list_pagination_ten_products_page_2(set_test_pagination_size, ten_tv_products): response = APIClient().get(f"{reverse('products-api-list')}?page=2") - assert len(response.data['results']) == 5 + results = response.data['results'] + assert response.status_code == 200 + assert len(results) == 5 + assert results[0]['id'] == ten_tv_products[5].id + assert results[4]['id'] == ten_tv_products[9].id assert response.data['count'] == 10 assert response.data['next'] is None - assert response.data['previous'] == "http://testserver/api/products/" \ No newline at end of file + assert response.data['previous'] == "http://testserver/api/products/" + + +@pytest.mark.django_db +def test_product_list_pagination_forty_three_products_page_4(set_test_pagination_size, forty_three_tv_products): + response = APIClient().get(f"{reverse('products-api-list')}?page=4") + results = response.data['results'] + assert response.status_code == 200 + assert len(results) == 5 + assert results[0]['id'] == forty_three_tv_products[15].id + assert results[4]['id'] == forty_three_tv_products[19].id + assert response.data['count'] == 43 + assert response.data['next'] == "http://testserver/api/products/?page=5" + assert response.data['previous'] == "http://testserver/api/products/?page=3" + + +@pytest.mark.django_db +def test_product_list_pagination_forty_three_products_page_9(set_test_pagination_size, forty_three_tv_products): + response = APIClient().get(f"{reverse('products-api-list')}?page=9") + results = response.data['results'] + assert response.status_code == 200 + assert len(results) == 3 + assert results[0]['id'] == forty_three_tv_products[40].id + assert results[2]['id'] == forty_three_tv_products[42].id + assert response.data['count'] == 43 + assert response.data['next'] is None + assert response.data['previous'] == "http://testserver/api/products/?page=8" + + +@pytest.mark.django_db +def test_delete_unallowed_method(tv_product): + response = APIClient().delete(reverse('products-api-detail', kwargs={'pk': tv_product.pk})) + assert response.status_code == 405 \ No newline at end of file From ce781388f82cc9a2483755b8045a44ea4b9310a9 Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Fri, 8 Mar 2024 15:48:16 +0100 Subject: [PATCH 10/15] added created_at for ten_tv_products --- Dshop/conftest.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Dshop/conftest.py b/Dshop/conftest.py index b958760..86384c9 100644 --- a/Dshop/conftest.py +++ b/Dshop/conftest.py @@ -1,3 +1,4 @@ +import datetime import pytest from dj_shop_cart.cart import get_cart_class from django.urls import reverse @@ -78,19 +79,22 @@ def ten_tv_products(): is_active=True ) tv_data = [ - {'name': 'TV AMOLED 32"', 'price': 599.00, 'full_description': 'High-quality 32-inch AMOLED TV.', 'category': category}, - {'name': 'Smart TV 40"', 'price': 899.00, 'full_description': '40-inch Smart TV with advanced features.', 'category': category}, - {'name': '4K Ultra HD TV 55"', 'price': 1299.00, 'full_description': '55-inch 4K Ultra HD TV for stunning visuals.', 'category': category}, - {'name': 'Curved TV 65"', 'price': 1999.00, 'full_description': 'Immersive 65-inch curved TV experience.', 'category': category}, - {'name': 'OLED TV 50"', 'price': 1699.00, 'full_description': '50-inch OLED TV with vibrant colors.', 'category': category}, - {'name': 'QLED TV 75"', 'price': 2999.00, 'full_description': '75-inch QLED TV for a cinematic viewing experience.', 'category': category}, - {'name': 'Android TV 43"', 'price': 799.00, 'full_description': '43-inch Android TV with a wide range of apps.', 'category': category}, - {'name': 'HD LED TV 24"', 'price': 299.00, 'full_description': '24-inch HD LED TV for compact spaces.', 'category': category}, - {'name': 'Outdoor TV 55"', 'price': 2499.00, 'full_description': '55-inch Outdoor TV for outdoor entertainment.', 'category': category}, - {'name': 'Gaming TV 50"', 'price': 1799.00, 'full_description': '50-inch Gaming TV with low input lag.', 'category': category}, + {'name': 'TV AMOLED 32"', 'price': 599.00, 'full_description': 'High-quality 32-inch AMOLED TV.', 'category': category, 'availability': 1}, + {'name': 'Smart TV 40"', 'price': 899.00, 'full_description': '40-inch Smart TV with advanced features.', 'category': category, 'availability': 3}, + {'name': '4K Ultra HD TV 55"', 'price': 1299.00, 'full_description': '55-inch 4K Ultra HD TV for stunning visuals.', 'category': category, 'availability': 7}, + {'name': 'Curved TV 65"', 'price': 1999.00, 'full_description': 'Immersive 65-inch curved TV experience.', 'category': category, 'availability': 14}, + {'name': 'OLED TV 50"', 'price': 1699.00, 'full_description': '50-inch OLED TV with vibrant colors.', 'category': category, 'availability': 90}, + {'name': 'QLED TV 75"', 'price': 2999.00, 'full_description': '75-inch QLED TV for a cinematic viewing experience.', 'category': category, 'availability': 99}, + {'name': 'Android TV 43"', 'price': 799.00, 'full_description': '43-inch Android TV with a wide range of apps.', 'category': category, 'availability': 110}, + {'name': 'HD LED TV 24"', 'price': 299.00, 'full_description': '24-inch HD LED TV for compact spaces.', 'category': category, 'availability': 99}, + {'name': 'Outdoor TV 55"', 'price': 2499.00, 'full_description': '55-inch Outdoor TV for outdoor entertainment.', 'category': category, 'availability': 99}, + {'name': 'Gaming TV 50"', 'price': 1799.00, 'full_description': '50-inch Gaming TV with low input lag.', 'category': category, 'availability': 99}, ] - return [Product.objects.create(**data) for data in tv_data] - + result = [] + for idx, tv in enumerate(tv_data): + tv['created_at'] = datetime.datetime.now() - datetime.timedelta(days=idx) + result.append(Product.objects.create(**tv)) + return result @fixture @pytest.mark.django_db def forty_three_tv_products(): From 0ec8867b1e501fb6b8736deb241e15d2a0997651 Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Sat, 9 Mar 2024 16:46:46 +0100 Subject: [PATCH 11/15] fix: deleted unused api_permissions --- Dshop/apps/products_catalogue/api_permissions.py | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 Dshop/apps/products_catalogue/api_permissions.py diff --git a/Dshop/apps/products_catalogue/api_permissions.py b/Dshop/apps/products_catalogue/api_permissions.py deleted file mode 100644 index dd713d2..0000000 --- a/Dshop/apps/products_catalogue/api_permissions.py +++ /dev/null @@ -1,5 +0,0 @@ -from rest_framework.permissions import BasePermission, SAFE_METHODS - -class IsStaffOrReadOnly(BasePermission): - def has_permission(self, request, view): - return (request.method in SAFE_METHODS) or request.user.is_staff == True From 85edd36685f88fc74539d6d35855eee3041d4fb4 Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Sat, 9 Mar 2024 17:26:31 +0100 Subject: [PATCH 12/15] test: changed test settings pagination --- Dshop/Dshop/settings_tests.py | 2 ++ .../tests/test_api_products.py | 18 ++++++++---------- Dshop/apps/users/conftest.py | 1 - Dshop/pytest.ini | 4 ++-- 4 files changed, 12 insertions(+), 13 deletions(-) create mode 100644 Dshop/Dshop/settings_tests.py diff --git a/Dshop/Dshop/settings_tests.py b/Dshop/Dshop/settings_tests.py new file mode 100644 index 0000000..190ba7a --- /dev/null +++ b/Dshop/Dshop/settings_tests.py @@ -0,0 +1,2 @@ +from Dshop.settings import * # noqa: W0401 +REST_FRAMEWORK['PAGE_SIZE'] = 5 # noqa: W0401 \ No newline at end of file diff --git a/Dshop/apps/products_catalogue/tests/test_api_products.py b/Dshop/apps/products_catalogue/tests/test_api_products.py index 3407826..5f87601 100644 --- a/Dshop/apps/products_catalogue/tests/test_api_products.py +++ b/Dshop/apps/products_catalogue/tests/test_api_products.py @@ -1,6 +1,7 @@ from rest_framework.test import APIClient import pytest from django.urls import reverse +from django.conf import settings def assert_active_object(data): @@ -39,16 +40,13 @@ def test_product_detail_404(): @pytest.fixture -def set_test_pagination_size(settings): - # alternative settings.REST_FRAMEWORK['PAGE_SIZE'] = 5 - original = settings.REST_FRAMEWORK - import copy - rest = copy.deepcopy(settings.REST_FRAMEWORK) - rest['PAGE_SIZE'] = 5 - settings.REST_FRAMEWORK = rest - yield - settings.REST_FRAMEWORK = original - +def set_test_pagination_size(settings, autouse=True): + settings.REST_FRAMEWORK['PAGE_SIZE'] = 5 + + +def test_pagination_size_in_tests(): + assert settings.REST_FRAMEWORK['PAGE_SIZE'] == 5 + # pagination size changed here: Dshop/Dshop/settings_tests.py @pytest.mark.django_db def test_product_list_empty(set_test_pagination_size): diff --git a/Dshop/apps/users/conftest.py b/Dshop/apps/users/conftest.py index 10dea54..77dc1f1 100644 --- a/Dshop/apps/users/conftest.py +++ b/Dshop/apps/users/conftest.py @@ -2,7 +2,6 @@ from django.contrib.auth import get_user_model from django.urls import reverse from rest_framework.authtoken.models import Token -from rest_framework.test import APIClient User = get_user_model() diff --git a/Dshop/pytest.ini b/Dshop/pytest.ini index a939796..3173719 100644 --- a/Dshop/pytest.ini +++ b/Dshop/pytest.ini @@ -1,5 +1,5 @@ [pytest] -DJANGO_SETTINGS_MODULE = Dshop.settings +DJANGO_SETTINGS_MODULE = Dshop.settings_tests python_files = tests.py test_*.py *_tests.py markers = - dj_shop_cart: tests for dj_shop_cart + dj_shop_cart: tests for dj_shop_cart \ No newline at end of file From 15727f90ef454b09a68bfe31f5a54996405c5bb2 Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Sat, 9 Mar 2024 18:25:06 +0100 Subject: [PATCH 13/15] fix: removed duplicated import --- Dshop/apps/products_catalogue/api_views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Dshop/apps/products_catalogue/api_views.py b/Dshop/apps/products_catalogue/api_views.py index a7cb09d..2179526 100644 --- a/Dshop/apps/products_catalogue/api_views.py +++ b/Dshop/apps/products_catalogue/api_views.py @@ -5,8 +5,6 @@ from rest_framework.permissions import AllowAny from rest_framework import status from dj_shop_cart.cart import get_cart_class -from rest_framework.permissions import AllowAny - from .models import Product from .serializers import CartReadSerializer, ProductSerializer, CartWriteSerializer from .filters import ProductFilter From c8cc1cb314b95f720c871d2eb4a2ff35af1e3fc2 Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Sun, 10 Mar 2024 14:41:19 +0100 Subject: [PATCH 14/15] test: removed duplicated authenticated_api_client, changed name to api_client_authenticated --- .../products_catalogue/tests/test_api_products.py | 11 ++--------- Dshop/conftest.py | 2 +- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Dshop/apps/products_catalogue/tests/test_api_products.py b/Dshop/apps/products_catalogue/tests/test_api_products.py index 59a7d13..ef79f99 100644 --- a/Dshop/apps/products_catalogue/tests/test_api_products.py +++ b/Dshop/apps/products_catalogue/tests/test_api_products.py @@ -38,13 +38,6 @@ def create_inactive_product(): ) -@pytest.fixture -def authenticated_api_client(api_client, user_instance_token): - api_client.credentials(HTTP_AUTHORIZATION=f'Token {user_instance_token.key}') - return api_client - - - @pytest.fixture def create_product_with_images(create_category): product = Product.objects.create( @@ -98,9 +91,9 @@ def assert_product_with_images(data): @pytest.mark.django_db -def test_product_detail_with_images(api_client_authed, create_product_with_images): +def test_product_detail_with_images(api_client_authenticated, create_product_with_images): url = reverse('products-api-detail', kwargs={'pk': create_product_with_images.id}) - response = api_client_authed.get(url) + response = api_client_authenticated.get(url) assert response.status_code == 200 assert_product_with_images(response.data) diff --git a/Dshop/conftest.py b/Dshop/conftest.py index 86384c9..8cbaa57 100644 --- a/Dshop/conftest.py +++ b/Dshop/conftest.py @@ -17,7 +17,7 @@ def api_client(): return APIClient() @pytest.fixture -def api_client_authed(): +def api_client_authenticated(): client = APIClient() user = User.objects.create_user(username='testuser', password='testpassword') client.force_authenticate(user) From 92101b627a220eaa1ff5c6fe69c0db1577beb584 Mon Sep 17 00:00:00 2001 From: Jan Gregorczyk Date: Sun, 10 Mar 2024 15:15:35 +0100 Subject: [PATCH 15/15] tests: refactor of products api detail tests, removal of unused fixture --- .../tests/test_api_products.py | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/Dshop/apps/products_catalogue/tests/test_api_products.py b/Dshop/apps/products_catalogue/tests/test_api_products.py index ef79f99..3add42b 100644 --- a/Dshop/apps/products_catalogue/tests/test_api_products.py +++ b/Dshop/apps/products_catalogue/tests/test_api_products.py @@ -3,8 +3,6 @@ from django.urls import reverse from django.conf import settings from apps.products_catalogue.models import Category, Product, ProductImage -# pylama:ignore=W0404, W0611 -from apps.users.conftest import login_url, login_data, user_instance, user_instance_token from PIL import Image from django.core.files.uploadedfile import SimpleUploadedFile import tempfile @@ -91,16 +89,15 @@ def assert_product_with_images(data): @pytest.mark.django_db -def test_product_detail_with_images(api_client_authenticated, create_product_with_images): +def test_product_detail_with_images(create_product_with_images): url = reverse('products-api-detail', kwargs={'pk': create_product_with_images.id}) - response = api_client_authenticated.get(url) - + response = APIClient().get(url) assert response.status_code == 200 assert_product_with_images(response.data) @pytest.mark.django_db -def test_get_list_one(set_test_pagination_size, tv_product, inactive_product): +def test_get_list_one(tv_product, inactive_product): url = reverse('products-api-list') response = APIClient().get(url) assert response.status_code == 200 @@ -120,17 +117,13 @@ def test_product_detail_404(): assert response.status_code == 404 -@pytest.fixture -def set_test_pagination_size(settings, autouse=True): - settings.REST_FRAMEWORK['PAGE_SIZE'] = 5 - - def test_pagination_size_in_tests(): assert settings.REST_FRAMEWORK['PAGE_SIZE'] == 5 # pagination size changed here: Dshop/Dshop/settings_tests.py + @pytest.mark.django_db -def test_product_list_empty(set_test_pagination_size): +def test_product_list_empty(): response = APIClient().get(reverse("products-api-list")) assert response.status_code == 200 assert response.data['results'] == [] @@ -139,24 +132,25 @@ def test_product_list_empty(set_test_pagination_size): assert response.data['next'] is None - @pytest.mark.django_db def test_product_detail(tv_product): url = reverse('products-api-detail', kwargs={'pk': tv_product.id}) response = APIClient().get(url) assert response.status_code == 200 + assert response.data + assert_active_object(response.data) @pytest.mark.django_db -def test_product_list_pagination_ten_products_page_too_far(set_test_pagination_size, tv_product): +def test_product_list_pagination_ten_products_page_too_far(tv_product): response = APIClient().get(f"{reverse('products-api-list')}?page=100") assert response.status_code == 404 @pytest.mark.parametrize("page_suffix", ["", "?page=1"]) @pytest.mark.django_db -def test_product_list_pagination_ten_products_page_1(set_test_pagination_size, page_suffix, ten_tv_products):#, ten_tv_products): +def test_product_list_pagination_ten_products_page_1(page_suffix, ten_tv_products): response = APIClient().get(reverse("products-api-list") + page_suffix) results = response.data['results'] assert len(results) == 5 @@ -168,7 +162,7 @@ def test_product_list_pagination_ten_products_page_1(set_test_pagination_size, p @pytest.mark.django_db -def test_product_list_pagination_ten_products_page_2(set_test_pagination_size, ten_tv_products): +def test_product_list_pagination_ten_products_page_2(ten_tv_products): response = APIClient().get(f"{reverse('products-api-list')}?page=2") results = response.data['results'] assert response.status_code == 200 @@ -181,7 +175,7 @@ def test_product_list_pagination_ten_products_page_2(set_test_pagination_size, t @pytest.mark.django_db -def test_product_list_pagination_forty_three_products_page_4(set_test_pagination_size, forty_three_tv_products): +def test_product_list_pagination_forty_three_products_page_4(forty_three_tv_products): response = APIClient().get(f"{reverse('products-api-list')}?page=4") results = response.data['results'] assert response.status_code == 200 @@ -194,7 +188,7 @@ def test_product_list_pagination_forty_three_products_page_4(set_test_pagination @pytest.mark.django_db -def test_product_list_pagination_forty_three_products_page_9(set_test_pagination_size, forty_three_tv_products): +def test_product_list_pagination_forty_three_products_page_9(forty_three_tv_products): response = APIClient().get(f"{reverse('products-api-list')}?page=9") results = response.data['results'] assert response.status_code == 200