From af25242799660362c708b7c75bd9308ee5a6d6c4 Mon Sep 17 00:00:00 2001 From: piyush-jaiswal Date: Fri, 22 Aug 2025 13:34:42 +0530 Subject: [PATCH 1/7] Add relationship tests --- tests/conftest.py | 44 ++++++++- tests/test_relationships.py | 186 ++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 tests/test_relationships.py diff --git a/tests/conftest.py b/tests/conftest.py index 6e1b963..0db66e7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,6 @@ from tests import utils - @pytest.fixture def client(): app.config["TESTING"] = True @@ -49,3 +48,46 @@ def _get_headers(email="testuser@example.com", password="testpassword"): return utils.get_auth_header(tokens["access_token"]) return _get_headers + + +@pytest.fixture +def create_category(client, create_authenticated_headers): + def _create(name, subcategories=None, headers=None): + if headers is None: + headers = create_authenticated_headers() + payload = {"name": name} + if subcategories is not None: + payload["subcategories"] = subcategories + return client.post("/category/create", json=payload, headers=headers) + + return _create + + +@pytest.fixture +def create_subcategory(client, create_authenticated_headers): + def _create(name, categories=None, products=None, headers=None): + if headers is None: + headers = create_authenticated_headers() + payload = {"name": name} + if categories is not None: + payload["categories"] = categories + if products is not None: + payload["products"] = products + return client.post("/subcategory/create", json=payload, headers=headers) + + return _create + + +@pytest.fixture +def create_product(client, create_authenticated_headers): + def _create(name, description=None, subcategories=None, headers=None): + if headers is None: + headers = create_authenticated_headers() + payload = {"name": name} + if description is not None: + payload["description"] = description + if subcategories is not None: + payload["subcategories"] = subcategories + return client.post("/product/create", json=payload, headers=headers) + + return _create diff --git a/tests/test_relationships.py b/tests/test_relationships.py new file mode 100644 index 0000000..391e0b6 --- /dev/null +++ b/tests/test_relationships.py @@ -0,0 +1,186 @@ +import pytest + +from app.models import Category, Subcategory, Product + + +class TestRelationships: + def _category_subcategory_ids(self, client, category_id): + with client.application.app_context(): + category = Category.query.get(category_id) + assert category is not None + return sorted([subcategory.id for subcategory in category.subcategories]) + + def _subcategory_category_ids(self, client, subcategory_id): + with client.application.app_context(): + subcategory = Subcategory.query.get(subcategory_id) + assert subcategory is not None + return sorted([category.id for category in subcategory.categories]) + + def _subcategory_product_ids(self, client, subcategory_id): + with client.application.app_context(): + subcategory = Subcategory.query.get(subcategory_id) + assert subcategory is not None + return sorted([product.id for product in subcategory.products]) + + def _product_subcategory_ids(self, client, product_id): + with client.application.app_context(): + product = Product.query.get(product_id) + assert product is not None + return sorted([subcategory.id for subcategory in product.subcategories]) + + def _category_product_ids_via_subcategories(self, client, category_id): + with client.application.app_context(): + category = Category.query.get(category_id) + assert category is not None + return sorted({product.id for subcategory in category.subcategories for product in subcategory.products.all()}) + + def test_create_category_with_subcategories(self, client, create_category, create_subcategory): + subcategory1 = create_subcategory("SC_A").get_json() + subcategory2 = create_subcategory("SC_B").get_json() + response = create_category("Cat_AB", subcategories=[subcategory1["id"], subcategory2["id"]]) + assert response.status_code == 201 + category = response.get_json() + + assert self._category_subcategory_ids(client, category["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) + assert category["id"] in self._subcategory_category_ids(client, subcategory1["id"]) + assert category["id"] in self._subcategory_category_ids(client, subcategory2["id"]) + + def test_create_subcategory_with_categories_and_products(self, client, create_subcategory, create_category, create_product): + category1 = create_category("C1").get_json() + category2 = create_category("C2").get_json() + product1 = create_product("P1", "des").get_json() + product2 = create_product("P2", "desc").get_json() + + response = create_subcategory("SC_C1C2_P1P2", categories=[category1["id"], category2["id"]], products=[product1["id"], product2["id"]]) + assert response.status_code == 201 + subcategory = response.get_json() + + assert self._subcategory_category_ids(client, subcategory["id"]) == sorted([category1["id"], category2["id"]]) + assert self._subcategory_product_ids(client, subcategory["id"]) == sorted([product1["id"], product2["id"]]) + + def test_create_product_with_subcategories_links_to_category_products(self, client, create_category, create_subcategory, create_product): + category = create_category("C").get_json() + subcategory = create_subcategory("SC", categories=[category["id"]]).get_json() + response = create_product("P", "desc", subcategories=[subcategory["id"]]) + assert response.status_code == 201 + product = response.get_json() + + assert subcategory["id"] in self._product_subcategory_ids(client, product["id"]) + assert product["id"] in self._category_product_ids_via_subcategories(client, category["id"]) + assert product["id"] in self._subcategory_product_ids(client, subcategory["id"]) + + def test_update_category_adds_subcategories(self, client, create_authenticated_headers, create_category, create_subcategory): + subcategory1 = create_subcategory("U_SC1").get_json() + subcategory2 = create_subcategory("U_SC2").get_json() + category = create_category("U_Cat", subcategories=[subcategory1["id"]]).get_json() + + headers = create_authenticated_headers() + update_response = client.put(f"/category/{category['id']}/update", json={"subcategories": [subcategory2["id"]]}, headers=headers) + assert update_response.status_code == 201 + + assert self._category_subcategory_ids(client, category["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) + + def test_update_subcategory_adds_categories_and_products(self, client, create_authenticated_headers, create_category, create_product, create_subcategory): + category1 = create_category("UC1").get_json() + category2 = create_category("UC2").get_json() + product1 = create_product("UP1").get_json() + product2 = create_product("UP2").get_json() + subcategory = create_subcategory("U_SC").get_json() + + headers = create_authenticated_headers() + update_response = client.put( + f"/subcategory/{subcategory['id']}/update", + json={"categories": [category1["id"], category2["id"]], "products": [product1["id"], product2["id"]]}, + headers=headers, + ) + assert update_response.status_code == 201 + + assert self._subcategory_category_ids(client, subcategory["id"]) == sorted([category1["id"], category2["id"]]) + assert self._subcategory_product_ids(client, subcategory["id"]) == sorted([product1["id"], product2["id"]]) + + def test_update_product_adds_subcategories(self, client, create_authenticated_headers, create_product, create_subcategory): + subcategory1 = create_subcategory("UPS1").get_json() + subcategory2 = create_subcategory("UPS2").get_json() + product = create_product("UP", "desc", subcategories=[subcategory1["id"]]).get_json() + + headers = create_authenticated_headers() + update_response = client.put(f"/product/{product['id']}/update", json={"subcategories": [subcategory2["id"]]}, headers=headers) + assert update_response.status_code == 201 + + assert self._product_subcategory_ids(client, product["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) + + def test_get_category_subcategories_empty(self, client, create_category): + category = create_category("Cat_NoSC").get_json() + assert self._category_subcategory_ids(client, category["id"]) == [] + + def test_get_category_subcategories_populated(self, client, create_category, create_subcategory): + subcategory1 = create_subcategory("SC1").get_json() + subcategory2 = create_subcategory("SC2").get_json() + category = create_category("Cat_WithSC", subcategories=[subcategory1["id"], subcategory2["id"]]).get_json() + + assert self._category_subcategory_ids(client, category["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) + + def test_get_category_products_empty(self, client, create_category): + category = create_category("Cat_NoProd").get_json() + assert set(self._category_product_ids_via_subcategories(client, category["id"])) == set() + + def test_get_category_products_populated_with_pagination(self, client, create_category, create_subcategory, create_product): + category = create_category("Cat_Prod").get_json() + subcategory = create_subcategory("SC_Prod", categories=[category["id"]]).get_json() + + product_ids = set() + for index in range(12): + product_resp = create_product(f"P{index}", "desc", subcategories=[subcategory["id"]]) + product_ids.add(product_resp.get_json().get("id")) + + page1 = client.get(f"/category/{category['id']}/products?page=1").get_json() + page2 = client.get(f"/category/{category['id']}/products?page=2").get_json() + assert len(page1["products"]) == 10 + assert len(page2["products"]) == 2 + + returned_product_ids = set(p["id"] for p in page1["products"] + page2["products"]) + assert returned_product_ids == product_ids + + def test_get_subcategory_categories_populated(self, client, create_category, create_subcategory): + category1 = create_category("C1").get_json() + category2 = create_category("C2").get_json() + subcategory = create_subcategory("SC_Cats", categories=[category1["id"], category2["id"]]).get_json() + + assert self._subcategory_category_ids(client, subcategory["id"]) == sorted([category1["id"], category2["id"]]) + + def test_get_subcategory_products_populated_with_pagination(self, client, create_subcategory, create_product): + subcategory = create_subcategory("SC_Pag").get_json() + + product_ids = set() + for index in range(11): + product_resp = create_product(f"SP{index}", "desc", subcategories=[subcategory["id"]]) + product_ids.add(product_resp.get_json().get("id")) + + page1 = client.get(f"/subcategory/{subcategory['id']}/products?page=1").get_json() + page2 = client.get(f"/subcategory/{subcategory['id']}/products?page=2").get_json() + assert len(page1["products"]) == 10 + assert len(page2["products"]) == 1 + + returned_product_ids = set(p["id"] for p in page1["products"] + page2["products"]) + assert returned_product_ids == product_ids + + def test_get_product_subcategories_populated(self, client, create_product, create_subcategory): + subcategory1 = create_subcategory("S1").get_json() + subcategory2 = create_subcategory("S2").get_json() + product = create_product("Prod_SC", "desc", subcategories=[subcategory1["id"], subcategory2["id"]]).get_json() + + assert self._product_subcategory_ids(client, product["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) + + @pytest.mark.parametrize( + "path", + [ + "/category/999999/subcategories", + "/category/999999/products", + "/subcategory/999999/categories", + "/subcategory/999999/products", + "/product/999999/subcategories", + ], + ) + def test_relationship_getters_404(self, client, path): + resp = client.get(path) + assert resp.status_code == 404 From 8fef72aec53ebc31d9618cbbf23f6b7dc457e9df Mon Sep 17 00:00:00 2001 From: piyush-jaiswal Date: Fri, 22 Aug 2025 13:34:59 +0530 Subject: [PATCH 2/7] Use fixtures from conftest --- tests/test_category.py | 11 ----------- tests/test_product.py | 15 --------------- tests/test_subcategory.py | 17 ----------------- 3 files changed, 43 deletions(-) diff --git a/tests/test_category.py b/tests/test_category.py index c4b8c0a..8a8279b 100644 --- a/tests/test_category.py +++ b/tests/test_category.py @@ -13,17 +13,6 @@ def setup(self, client): with client.application.app_context(): assert Category.query.count() == 0 - @pytest.fixture - def create_category(self, create_authenticated_headers): - def _create(name, headers=None): - if headers is None: - headers = create_authenticated_headers() - return self.client.post( - "/category/create", json={"name": name}, headers=headers - ) - - return _create - def _count_categories(self): with self.client.application.app_context(): return Category.query.count() diff --git a/tests/test_product.py b/tests/test_product.py index f1502cb..e1a7e31 100644 --- a/tests/test_product.py +++ b/tests/test_product.py @@ -14,21 +14,6 @@ def setup(self, client): with client.application.app_context(): assert Product.query.count() == 0 - @pytest.fixture - def create_product(self, create_authenticated_headers): - def _create(name, description=None, subcategories=None, headers=None): - if headers is None: - headers = create_authenticated_headers() - payload = {"name": name} - if description is not None: - payload["description"] = description - if subcategories is not None: - payload["subcategories"] = subcategories - return self.client.post( - "/product/create", json=payload, headers=headers - ) - return _create - def _count_products(self): with self.client.application.app_context(): return Product.query.count() diff --git a/tests/test_subcategory.py b/tests/test_subcategory.py index 0821f49..77d2881 100644 --- a/tests/test_subcategory.py +++ b/tests/test_subcategory.py @@ -13,21 +13,6 @@ def setup(self, client): with client.application.app_context(): assert Subcategory.query.count() == 0 - @pytest.fixture - def create_subcategory(self, create_authenticated_headers): - def _create(name, categories=None, products=None, headers=None): - if headers is None: - headers = create_authenticated_headers() - payload = {"name": name} - if categories is not None: - payload["categories"] = categories - if products is not None: - payload["products"] = products - return self.client.post( - "/subcategory/create", json=payload, headers=headers - ) - return _create - def _count_subcategories(self): with self.client.application.app_context(): return Subcategory.query.count() @@ -59,8 +44,6 @@ def test_create_subcategory_duplicate_name(self, create_subcategory): assert self._count_subcategories() == 1 self._verify_subcategory_in_db(self.TEST_SUBCATEGORY_NAME) - # TODO: Add tests for creation with categories and products when those fixtures/utilities are available - def test_get_subcategory_by_id(self, create_subcategory): response = create_subcategory("Laptops") data = response.get_json() From 8f8d791ea1b40fd0d4c494beaca204f8b006b41d Mon Sep 17 00:00:00 2001 From: piyush-jaiswal Date: Fri, 22 Aug 2025 14:15:02 +0530 Subject: [PATCH 3/7] Add tests for empty relationships and setup client autouse fixture --- tests/test_relationships.py | 159 +++++++++++++++++++++++++----------- 1 file changed, 111 insertions(+), 48 deletions(-) diff --git a/tests/test_relationships.py b/tests/test_relationships.py index 391e0b6..b56688e 100644 --- a/tests/test_relationships.py +++ b/tests/test_relationships.py @@ -4,48 +4,56 @@ class TestRelationships: - def _category_subcategory_ids(self, client, category_id): + @pytest.fixture(autouse=True) + def setup(self, client): + self.client = client with client.application.app_context(): + assert Category.query.count() == 0 + assert Subcategory.query.count() == 0 + assert Product.query.count() == 0 + + def _category_subcategory_ids(self, category_id): + with self.client.application.app_context(): category = Category.query.get(category_id) assert category is not None return sorted([subcategory.id for subcategory in category.subcategories]) - def _subcategory_category_ids(self, client, subcategory_id): - with client.application.app_context(): + def _subcategory_category_ids(self, subcategory_id): + with self.client.application.app_context(): subcategory = Subcategory.query.get(subcategory_id) assert subcategory is not None return sorted([category.id for category in subcategory.categories]) - def _subcategory_product_ids(self, client, subcategory_id): - with client.application.app_context(): + def _subcategory_product_ids(self, subcategory_id): + with self.client.application.app_context(): subcategory = Subcategory.query.get(subcategory_id) assert subcategory is not None return sorted([product.id for product in subcategory.products]) - def _product_subcategory_ids(self, client, product_id): - with client.application.app_context(): + def _product_subcategory_ids(self, product_id): + with self.client.application.app_context(): product = Product.query.get(product_id) assert product is not None return sorted([subcategory.id for subcategory in product.subcategories]) - def _category_product_ids_via_subcategories(self, client, category_id): - with client.application.app_context(): + def _category_product_ids_via_subcategories(self, category_id): + with self.client.application.app_context(): category = Category.query.get(category_id) assert category is not None return sorted({product.id for subcategory in category.subcategories for product in subcategory.products.all()}) - def test_create_category_with_subcategories(self, client, create_category, create_subcategory): + def test_create_category_with_subcategories(self, create_category, create_subcategory): subcategory1 = create_subcategory("SC_A").get_json() subcategory2 = create_subcategory("SC_B").get_json() response = create_category("Cat_AB", subcategories=[subcategory1["id"], subcategory2["id"]]) assert response.status_code == 201 category = response.get_json() - assert self._category_subcategory_ids(client, category["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) - assert category["id"] in self._subcategory_category_ids(client, subcategory1["id"]) - assert category["id"] in self._subcategory_category_ids(client, subcategory2["id"]) + assert self._category_subcategory_ids(category["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) + assert category["id"] in self._subcategory_category_ids(subcategory1["id"]) + assert category["id"] in self._subcategory_category_ids(subcategory2["id"]) - def test_create_subcategory_with_categories_and_products(self, client, create_subcategory, create_category, create_product): + def test_create_subcategory_with_categories_and_products(self, create_subcategory, create_category, create_product): category1 = create_category("C1").get_json() category2 = create_category("C2").get_json() product1 = create_product("P1", "des").get_json() @@ -55,32 +63,32 @@ def test_create_subcategory_with_categories_and_products(self, client, create_su assert response.status_code == 201 subcategory = response.get_json() - assert self._subcategory_category_ids(client, subcategory["id"]) == sorted([category1["id"], category2["id"]]) - assert self._subcategory_product_ids(client, subcategory["id"]) == sorted([product1["id"], product2["id"]]) + assert self._subcategory_category_ids(subcategory["id"]) == sorted([category1["id"], category2["id"]]) + assert self._subcategory_product_ids(subcategory["id"]) == sorted([product1["id"], product2["id"]]) - def test_create_product_with_subcategories_links_to_category_products(self, client, create_category, create_subcategory, create_product): + def test_create_product_with_subcategories_links_to_category_products(self, create_category, create_subcategory, create_product): category = create_category("C").get_json() subcategory = create_subcategory("SC", categories=[category["id"]]).get_json() response = create_product("P", "desc", subcategories=[subcategory["id"]]) assert response.status_code == 201 product = response.get_json() - assert subcategory["id"] in self._product_subcategory_ids(client, product["id"]) - assert product["id"] in self._category_product_ids_via_subcategories(client, category["id"]) - assert product["id"] in self._subcategory_product_ids(client, subcategory["id"]) + assert subcategory["id"] in self._product_subcategory_ids(product["id"]) + assert product["id"] in self._category_product_ids_via_subcategories(category["id"]) + assert product["id"] in self._subcategory_product_ids(subcategory["id"]) - def test_update_category_adds_subcategories(self, client, create_authenticated_headers, create_category, create_subcategory): + def test_update_category_adds_subcategories(self, create_authenticated_headers, create_category, create_subcategory): subcategory1 = create_subcategory("U_SC1").get_json() subcategory2 = create_subcategory("U_SC2").get_json() category = create_category("U_Cat", subcategories=[subcategory1["id"]]).get_json() headers = create_authenticated_headers() - update_response = client.put(f"/category/{category['id']}/update", json={"subcategories": [subcategory2["id"]]}, headers=headers) + update_response = self.client.put(f"/category/{category['id']}/update", json={"subcategories": [subcategory2["id"]]}, headers=headers) assert update_response.status_code == 201 - assert self._category_subcategory_ids(client, category["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) + assert self._category_subcategory_ids(category["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) - def test_update_subcategory_adds_categories_and_products(self, client, create_authenticated_headers, create_category, create_product, create_subcategory): + def test_update_subcategory_adds_categories_and_products(self, create_authenticated_headers, create_category, create_product, create_subcategory): category1 = create_category("UC1").get_json() category2 = create_category("UC2").get_json() product1 = create_product("UP1").get_json() @@ -88,43 +96,59 @@ def test_update_subcategory_adds_categories_and_products(self, client, create_au subcategory = create_subcategory("U_SC").get_json() headers = create_authenticated_headers() - update_response = client.put( + update_response = self.client.put( f"/subcategory/{subcategory['id']}/update", json={"categories": [category1["id"], category2["id"]], "products": [product1["id"], product2["id"]]}, headers=headers, ) assert update_response.status_code == 201 - assert self._subcategory_category_ids(client, subcategory["id"]) == sorted([category1["id"], category2["id"]]) - assert self._subcategory_product_ids(client, subcategory["id"]) == sorted([product1["id"], product2["id"]]) + assert self._subcategory_category_ids(subcategory["id"]) == sorted([category1["id"], category2["id"]]) + assert self._subcategory_product_ids(subcategory["id"]) == sorted([product1["id"], product2["id"]]) - def test_update_product_adds_subcategories(self, client, create_authenticated_headers, create_product, create_subcategory): + def test_update_product_adds_subcategories(self, create_authenticated_headers, create_product, create_subcategory): subcategory1 = create_subcategory("UPS1").get_json() subcategory2 = create_subcategory("UPS2").get_json() product = create_product("UP", "desc", subcategories=[subcategory1["id"]]).get_json() headers = create_authenticated_headers() - update_response = client.put(f"/product/{product['id']}/update", json={"subcategories": [subcategory2["id"]]}, headers=headers) + update_response = self.client.put(f"/product/{product['id']}/update", json={"subcategories": [subcategory2["id"]]}, headers=headers) assert update_response.status_code == 201 - assert self._product_subcategory_ids(client, product["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) + assert self._product_subcategory_ids(product["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) - def test_get_category_subcategories_empty(self, client, create_category): + def test_get_category_subcategories_empty(self, create_category): category = create_category("Cat_NoSC").get_json() - assert self._category_subcategory_ids(client, category["id"]) == [] + resp = self.client.get(f"/category/{category['id']}/subcategories") + + assert resp.status_code == 200 + data = resp.get_json() + assert "subcategories" in data + assert data["subcategories"] == [] - def test_get_category_subcategories_populated(self, client, create_category, create_subcategory): + def test_get_category_subcategories_populated(self, create_category, create_subcategory): subcategory1 = create_subcategory("SC1").get_json() subcategory2 = create_subcategory("SC2").get_json() category = create_category("Cat_WithSC", subcategories=[subcategory1["id"], subcategory2["id"]]).get_json() - assert self._category_subcategory_ids(client, category["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) + resp = self.client.get(f"/category/{category['id']}/subcategories") - def test_get_category_products_empty(self, client, create_category): + assert resp.status_code == 200 + data = resp.get_json() + assert "subcategories" in data + returned_ids = sorted([sc["id"] for sc in data["subcategories"]]) + assert returned_ids == sorted([subcategory1["id"], subcategory2["id"]]) + + def test_get_category_products_empty(self, create_category): category = create_category("Cat_NoProd").get_json() - assert set(self._category_product_ids_via_subcategories(client, category["id"])) == set() + resp = self.client.get(f"/category/{category['id']}/products") + + assert resp.status_code == 200 + data = resp.get_json() + assert "products" in data + assert data["products"] == [] - def test_get_category_products_populated_with_pagination(self, client, create_category, create_subcategory, create_product): + def test_get_category_products_populated_with_pagination(self, create_category, create_subcategory, create_product): category = create_category("Cat_Prod").get_json() subcategory = create_subcategory("SC_Prod", categories=[category["id"]]).get_json() @@ -133,22 +157,46 @@ def test_get_category_products_populated_with_pagination(self, client, create_ca product_resp = create_product(f"P{index}", "desc", subcategories=[subcategory["id"]]) product_ids.add(product_resp.get_json().get("id")) - page1 = client.get(f"/category/{category['id']}/products?page=1").get_json() - page2 = client.get(f"/category/{category['id']}/products?page=2").get_json() + page1 = self.client.get(f"/category/{category['id']}/products?page=1").get_json() + page2 = self.client.get(f"/category/{category['id']}/products?page=2").get_json() assert len(page1["products"]) == 10 assert len(page2["products"]) == 2 returned_product_ids = set(p["id"] for p in page1["products"] + page2["products"]) assert returned_product_ids == product_ids - def test_get_subcategory_categories_populated(self, client, create_category, create_subcategory): + def test_get_subcategory_categories_empty(self, create_subcategory): + subcategory = create_subcategory("SC_NoCat").get_json() + resp = self.client.get(f"/subcategory/{subcategory['id']}/categories") + + assert resp.status_code == 200 + data = resp.get_json() + assert "categories" in data + assert data["categories"] == [] + + def test_get_subcategory_categories_populated(self, create_category, create_subcategory): category1 = create_category("C1").get_json() category2 = create_category("C2").get_json() subcategory = create_subcategory("SC_Cats", categories=[category1["id"], category2["id"]]).get_json() - assert self._subcategory_category_ids(client, subcategory["id"]) == sorted([category1["id"], category2["id"]]) + resp = self.client.get(f"/subcategory/{subcategory['id']}/categories") + + assert resp.status_code == 200 + data = resp.get_json() + assert "categories" in data + returned_ids = sorted([cat["id"] for cat in data["categories"]]) + assert returned_ids == sorted([category1["id"], category2["id"]]) + + def test_get_subcategory_products_empty(self, create_subcategory): + subcategory = create_subcategory("SC_NoProd").get_json() + resp = self.client.get(f"/subcategory/{subcategory['id']}/products") - def test_get_subcategory_products_populated_with_pagination(self, client, create_subcategory, create_product): + assert resp.status_code == 200 + data = resp.get_json() + assert "products" in data + assert data["products"] == [] + + def test_get_subcategory_products_populated_with_pagination(self, create_subcategory, create_product): subcategory = create_subcategory("SC_Pag").get_json() product_ids = set() @@ -156,20 +204,35 @@ def test_get_subcategory_products_populated_with_pagination(self, client, create product_resp = create_product(f"SP{index}", "desc", subcategories=[subcategory["id"]]) product_ids.add(product_resp.get_json().get("id")) - page1 = client.get(f"/subcategory/{subcategory['id']}/products?page=1").get_json() - page2 = client.get(f"/subcategory/{subcategory['id']}/products?page=2").get_json() + page1 = self.client.get(f"/subcategory/{subcategory['id']}/products?page=1").get_json() + page2 = self.client.get(f"/subcategory/{subcategory['id']}/products?page=2").get_json() assert len(page1["products"]) == 10 assert len(page2["products"]) == 1 returned_product_ids = set(p["id"] for p in page1["products"] + page2["products"]) assert returned_product_ids == product_ids - def test_get_product_subcategories_populated(self, client, create_product, create_subcategory): + def test_get_product_subcategories_empty(self, create_product): + product = create_product("Prod_NoSC", "desc").get_json() + resp = self.client.get(f"/product/{product['id']}/subcategories") + + assert resp.status_code == 200 + data = resp.get_json() + assert "subcategories" in data + assert data["subcategories"] == [] + + def test_get_product_subcategories_populated(self, create_product, create_subcategory): subcategory1 = create_subcategory("S1").get_json() subcategory2 = create_subcategory("S2").get_json() product = create_product("Prod_SC", "desc", subcategories=[subcategory1["id"], subcategory2["id"]]).get_json() - assert self._product_subcategory_ids(client, product["id"]) == sorted([subcategory1["id"], subcategory2["id"]]) + resp = self.client.get(f"/product/{product['id']}/subcategories") + + assert resp.status_code == 200 + data = resp.get_json() + assert "subcategories" in data + returned_ids = sorted([sc["id"] for sc in data["subcategories"]]) + assert returned_ids == sorted([subcategory1["id"], subcategory2["id"]]) @pytest.mark.parametrize( "path", @@ -181,6 +244,6 @@ def test_get_product_subcategories_populated(self, client, create_product, creat "/product/999999/subcategories", ], ) - def test_relationship_getters_404(self, client, path): - resp = client.get(path) + def test_relationship_getters_404(self, path): + resp = self.client.get(path) assert resp.status_code == 404 From 433f43b92a503f8e38528b5418727dfafba3ea4a Mon Sep 17 00:00:00 2001 From: piyush-jaiswal Date: Fri, 22 Aug 2025 14:16:18 +0530 Subject: [PATCH 4/7] remove redundant tests --- tests/test_subcategory.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/tests/test_subcategory.py b/tests/test_subcategory.py index 77d2881..4429dfb 100644 --- a/tests/test_subcategory.py +++ b/tests/test_subcategory.py @@ -156,27 +156,3 @@ def test_delete_subcategory_token_error(self, get_headers, create_subcategory, c utils.verify_token_error_response(delete_resp, expected_code) self._verify_subcategory_in_db("DeleteTokenError") - - def test_get_subcategory_categories_empty(self, create_subcategory): - response = create_subcategory("NoCatRel") - data = response.get_json() - sc_id = data["id"] - - resp = self.client.get(f"/subcategory/{sc_id}/categories") - - assert resp.status_code == 200 - data = resp.get_json() - assert "categories" in data - assert data["categories"] == [] - - def test_get_subcategory_products_empty(self, create_subcategory): - response = create_subcategory("NoProdRel") - data = response.get_json() - sc_id = data["id"] - - resp = self.client.get(f"/subcategory/{sc_id}/products") - - assert resp.status_code == 200 - data = resp.get_json() - assert "products" in data - assert data["products"] == [] From f50861071975103ba25ef31982ed0463de7efce9 Mon Sep 17 00:00:00 2001 From: piyush-jaiswal Date: Fri, 22 Aug 2025 14:31:55 +0530 Subject: [PATCH 5/7] Refactor to assert in helper func --- tests/test_relationships.py | 59 ++++++++++--------------------------- 1 file changed, 16 insertions(+), 43 deletions(-) diff --git a/tests/test_relationships.py b/tests/test_relationships.py index b56688e..36f9756 100644 --- a/tests/test_relationships.py +++ b/tests/test_relationships.py @@ -42,6 +42,14 @@ def _category_product_ids_via_subcategories(self, category_id): assert category is not None return sorted({product.id for subcategory in category.subcategories for product in subcategory.products.all()}) + def _assert_related_collection(self, resp, key, expected_ids=[], status_code=200): + assert resp.status_code == status_code + data = resp.get_json() + assert key in data + returned_ids = sorted([item["id"] for item in data[key]]) + assert returned_ids == sorted(expected_ids) + + def test_create_category_with_subcategories(self, create_category, create_subcategory): subcategory1 = create_subcategory("SC_A").get_json() subcategory2 = create_subcategory("SC_B").get_json() @@ -120,11 +128,7 @@ def test_update_product_adds_subcategories(self, create_authenticated_headers, c def test_get_category_subcategories_empty(self, create_category): category = create_category("Cat_NoSC").get_json() resp = self.client.get(f"/category/{category['id']}/subcategories") - - assert resp.status_code == 200 - data = resp.get_json() - assert "subcategories" in data - assert data["subcategories"] == [] + self._assert_related_collection(resp, "subcategories") def test_get_category_subcategories_populated(self, create_category, create_subcategory): subcategory1 = create_subcategory("SC1").get_json() @@ -132,21 +136,12 @@ def test_get_category_subcategories_populated(self, create_category, create_subc category = create_category("Cat_WithSC", subcategories=[subcategory1["id"], subcategory2["id"]]).get_json() resp = self.client.get(f"/category/{category['id']}/subcategories") - - assert resp.status_code == 200 - data = resp.get_json() - assert "subcategories" in data - returned_ids = sorted([sc["id"] for sc in data["subcategories"]]) - assert returned_ids == sorted([subcategory1["id"], subcategory2["id"]]) + self._assert_related_collection(resp, "subcategories", expected_ids=[subcategory1["id"], subcategory2["id"]]) def test_get_category_products_empty(self, create_category): category = create_category("Cat_NoProd").get_json() resp = self.client.get(f"/category/{category['id']}/products") - - assert resp.status_code == 200 - data = resp.get_json() - assert "products" in data - assert data["products"] == [] + self._assert_related_collection(resp, "products") def test_get_category_products_populated_with_pagination(self, create_category, create_subcategory, create_product): category = create_category("Cat_Prod").get_json() @@ -168,11 +163,7 @@ def test_get_category_products_populated_with_pagination(self, create_category, def test_get_subcategory_categories_empty(self, create_subcategory): subcategory = create_subcategory("SC_NoCat").get_json() resp = self.client.get(f"/subcategory/{subcategory['id']}/categories") - - assert resp.status_code == 200 - data = resp.get_json() - assert "categories" in data - assert data["categories"] == [] + self._assert_related_collection(resp, "categories") def test_get_subcategory_categories_populated(self, create_category, create_subcategory): category1 = create_category("C1").get_json() @@ -180,21 +171,12 @@ def test_get_subcategory_categories_populated(self, create_category, create_subc subcategory = create_subcategory("SC_Cats", categories=[category1["id"], category2["id"]]).get_json() resp = self.client.get(f"/subcategory/{subcategory['id']}/categories") - - assert resp.status_code == 200 - data = resp.get_json() - assert "categories" in data - returned_ids = sorted([cat["id"] for cat in data["categories"]]) - assert returned_ids == sorted([category1["id"], category2["id"]]) + self._assert_related_collection(resp, "categories", expected_ids=[category1["id"], category2["id"]]) def test_get_subcategory_products_empty(self, create_subcategory): subcategory = create_subcategory("SC_NoProd").get_json() resp = self.client.get(f"/subcategory/{subcategory['id']}/products") - - assert resp.status_code == 200 - data = resp.get_json() - assert "products" in data - assert data["products"] == [] + self._assert_related_collection(resp, "products") def test_get_subcategory_products_populated_with_pagination(self, create_subcategory, create_product): subcategory = create_subcategory("SC_Pag").get_json() @@ -215,11 +197,7 @@ def test_get_subcategory_products_populated_with_pagination(self, create_subcate def test_get_product_subcategories_empty(self, create_product): product = create_product("Prod_NoSC", "desc").get_json() resp = self.client.get(f"/product/{product['id']}/subcategories") - - assert resp.status_code == 200 - data = resp.get_json() - assert "subcategories" in data - assert data["subcategories"] == [] + self._assert_related_collection(resp, "subcategories") def test_get_product_subcategories_populated(self, create_product, create_subcategory): subcategory1 = create_subcategory("S1").get_json() @@ -227,12 +205,7 @@ def test_get_product_subcategories_populated(self, create_product, create_subcat product = create_product("Prod_SC", "desc", subcategories=[subcategory1["id"], subcategory2["id"]]).get_json() resp = self.client.get(f"/product/{product['id']}/subcategories") - - assert resp.status_code == 200 - data = resp.get_json() - assert "subcategories" in data - returned_ids = sorted([sc["id"] for sc in data["subcategories"]]) - assert returned_ids == sorted([subcategory1["id"], subcategory2["id"]]) + self._assert_related_collection(resp, "subcategories", expected_ids=[subcategory1["id"], subcategory2["id"]]) @pytest.mark.parametrize( "path", From 97949975443ef23f806d35159b4249f3162bdf07 Mon Sep 17 00:00:00 2001 From: piyush-jaiswal Date: Fri, 22 Aug 2025 14:33:43 +0530 Subject: [PATCH 6/7] formatting --- tests/test_relationships.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_relationships.py b/tests/test_relationships.py index 36f9756..48f632c 100644 --- a/tests/test_relationships.py +++ b/tests/test_relationships.py @@ -49,7 +49,6 @@ def _assert_related_collection(self, resp, key, expected_ids=[], status_code=200 returned_ids = sorted([item["id"] for item in data[key]]) assert returned_ids == sorted(expected_ids) - def test_create_category_with_subcategories(self, create_category, create_subcategory): subcategory1 = create_subcategory("SC_A").get_json() subcategory2 = create_subcategory("SC_B").get_json() From 06a60623443551c8a1832cb2c3daf2821fd79199 Mon Sep 17 00:00:00 2001 From: piyush-jaiswal Date: Fri, 22 Aug 2025 16:09:14 +0530 Subject: [PATCH 7/7] Use immutable default value to prevent state leak between calls --- tests/test_relationships.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_relationships.py b/tests/test_relationships.py index 48f632c..188bb96 100644 --- a/tests/test_relationships.py +++ b/tests/test_relationships.py @@ -42,11 +42,12 @@ def _category_product_ids_via_subcategories(self, category_id): assert category is not None return sorted({product.id for subcategory in category.subcategories for product in subcategory.products.all()}) - def _assert_related_collection(self, resp, key, expected_ids=[], status_code=200): + def _assert_related_collection(self, resp, key, expected_ids=None, status_code=200): assert resp.status_code == status_code data = resp.get_json() assert key in data returned_ids = sorted([item["id"] for item in data[key]]) + expected_ids = expected_ids or [] assert returned_ids == sorted(expected_ids) def test_create_category_with_subcategories(self, create_category, create_subcategory):