Skip to content

Commit 4e166d6

Browse files
Merge pull request #13 from piyush-jaiswal/feature/add-relationship-tests
Add relationship tests
2 parents c23fa7d + 06a6062 commit 4e166d6

File tree

5 files changed

+265
-68
lines changed

5 files changed

+265
-68
lines changed

tests/conftest.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from tests import utils
1111

1212

13-
1413
@pytest.fixture
1514
def client():
1615
app.config["TESTING"] = True
@@ -49,3 +48,46 @@ def _get_headers(email="[email protected]", password="testpassword"):
4948
return utils.get_auth_header(tokens["access_token"])
5049

5150
return _get_headers
51+
52+
53+
@pytest.fixture
54+
def create_category(client, create_authenticated_headers):
55+
def _create(name, subcategories=None, headers=None):
56+
if headers is None:
57+
headers = create_authenticated_headers()
58+
payload = {"name": name}
59+
if subcategories is not None:
60+
payload["subcategories"] = subcategories
61+
return client.post("/category/create", json=payload, headers=headers)
62+
63+
return _create
64+
65+
66+
@pytest.fixture
67+
def create_subcategory(client, create_authenticated_headers):
68+
def _create(name, categories=None, products=None, headers=None):
69+
if headers is None:
70+
headers = create_authenticated_headers()
71+
payload = {"name": name}
72+
if categories is not None:
73+
payload["categories"] = categories
74+
if products is not None:
75+
payload["products"] = products
76+
return client.post("/subcategory/create", json=payload, headers=headers)
77+
78+
return _create
79+
80+
81+
@pytest.fixture
82+
def create_product(client, create_authenticated_headers):
83+
def _create(name, description=None, subcategories=None, headers=None):
84+
if headers is None:
85+
headers = create_authenticated_headers()
86+
payload = {"name": name}
87+
if description is not None:
88+
payload["description"] = description
89+
if subcategories is not None:
90+
payload["subcategories"] = subcategories
91+
return client.post("/product/create", json=payload, headers=headers)
92+
93+
return _create

tests/test_category.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,6 @@ def setup(self, client):
1313
with client.application.app_context():
1414
assert Category.query.count() == 0
1515

16-
@pytest.fixture
17-
def create_category(self, create_authenticated_headers):
18-
def _create(name, headers=None):
19-
if headers is None:
20-
headers = create_authenticated_headers()
21-
return self.client.post(
22-
"/category/create", json={"name": name}, headers=headers
23-
)
24-
25-
return _create
26-
2716
def _count_categories(self):
2817
with self.client.application.app_context():
2918
return Category.query.count()

tests/test_product.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,6 @@ def setup(self, client):
1414
with client.application.app_context():
1515
assert Product.query.count() == 0
1616

17-
@pytest.fixture
18-
def create_product(self, create_authenticated_headers):
19-
def _create(name, description=None, subcategories=None, headers=None):
20-
if headers is None:
21-
headers = create_authenticated_headers()
22-
payload = {"name": name}
23-
if description is not None:
24-
payload["description"] = description
25-
if subcategories is not None:
26-
payload["subcategories"] = subcategories
27-
return self.client.post(
28-
"/product/create", json=payload, headers=headers
29-
)
30-
return _create
31-
3217
def _count_products(self):
3318
with self.client.application.app_context():
3419
return Product.query.count()

tests/test_relationships.py

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
import pytest
2+
3+
from app.models import Category, Subcategory, Product
4+
5+
6+
class TestRelationships:
7+
@pytest.fixture(autouse=True)
8+
def setup(self, client):
9+
self.client = client
10+
with client.application.app_context():
11+
assert Category.query.count() == 0
12+
assert Subcategory.query.count() == 0
13+
assert Product.query.count() == 0
14+
15+
def _category_subcategory_ids(self, category_id):
16+
with self.client.application.app_context():
17+
category = Category.query.get(category_id)
18+
assert category is not None
19+
return sorted([subcategory.id for subcategory in category.subcategories])
20+
21+
def _subcategory_category_ids(self, subcategory_id):
22+
with self.client.application.app_context():
23+
subcategory = Subcategory.query.get(subcategory_id)
24+
assert subcategory is not None
25+
return sorted([category.id for category in subcategory.categories])
26+
27+
def _subcategory_product_ids(self, subcategory_id):
28+
with self.client.application.app_context():
29+
subcategory = Subcategory.query.get(subcategory_id)
30+
assert subcategory is not None
31+
return sorted([product.id for product in subcategory.products])
32+
33+
def _product_subcategory_ids(self, product_id):
34+
with self.client.application.app_context():
35+
product = Product.query.get(product_id)
36+
assert product is not None
37+
return sorted([subcategory.id for subcategory in product.subcategories])
38+
39+
def _category_product_ids_via_subcategories(self, category_id):
40+
with self.client.application.app_context():
41+
category = Category.query.get(category_id)
42+
assert category is not None
43+
return sorted({product.id for subcategory in category.subcategories for product in subcategory.products.all()})
44+
45+
def _assert_related_collection(self, resp, key, expected_ids=None, status_code=200):
46+
assert resp.status_code == status_code
47+
data = resp.get_json()
48+
assert key in data
49+
returned_ids = sorted([item["id"] for item in data[key]])
50+
expected_ids = expected_ids or []
51+
assert returned_ids == sorted(expected_ids)
52+
53+
def test_create_category_with_subcategories(self, create_category, create_subcategory):
54+
subcategory1 = create_subcategory("SC_A").get_json()
55+
subcategory2 = create_subcategory("SC_B").get_json()
56+
response = create_category("Cat_AB", subcategories=[subcategory1["id"], subcategory2["id"]])
57+
assert response.status_code == 201
58+
category = response.get_json()
59+
60+
assert self._category_subcategory_ids(category["id"]) == sorted([subcategory1["id"], subcategory2["id"]])
61+
assert category["id"] in self._subcategory_category_ids(subcategory1["id"])
62+
assert category["id"] in self._subcategory_category_ids(subcategory2["id"])
63+
64+
def test_create_subcategory_with_categories_and_products(self, create_subcategory, create_category, create_product):
65+
category1 = create_category("C1").get_json()
66+
category2 = create_category("C2").get_json()
67+
product1 = create_product("P1", "des").get_json()
68+
product2 = create_product("P2", "desc").get_json()
69+
70+
response = create_subcategory("SC_C1C2_P1P2", categories=[category1["id"], category2["id"]], products=[product1["id"], product2["id"]])
71+
assert response.status_code == 201
72+
subcategory = response.get_json()
73+
74+
assert self._subcategory_category_ids(subcategory["id"]) == sorted([category1["id"], category2["id"]])
75+
assert self._subcategory_product_ids(subcategory["id"]) == sorted([product1["id"], product2["id"]])
76+
77+
def test_create_product_with_subcategories_links_to_category_products(self, create_category, create_subcategory, create_product):
78+
category = create_category("C").get_json()
79+
subcategory = create_subcategory("SC", categories=[category["id"]]).get_json()
80+
response = create_product("P", "desc", subcategories=[subcategory["id"]])
81+
assert response.status_code == 201
82+
product = response.get_json()
83+
84+
assert subcategory["id"] in self._product_subcategory_ids(product["id"])
85+
assert product["id"] in self._category_product_ids_via_subcategories(category["id"])
86+
assert product["id"] in self._subcategory_product_ids(subcategory["id"])
87+
88+
def test_update_category_adds_subcategories(self, create_authenticated_headers, create_category, create_subcategory):
89+
subcategory1 = create_subcategory("U_SC1").get_json()
90+
subcategory2 = create_subcategory("U_SC2").get_json()
91+
category = create_category("U_Cat", subcategories=[subcategory1["id"]]).get_json()
92+
93+
headers = create_authenticated_headers()
94+
update_response = self.client.put(f"/category/{category['id']}/update", json={"subcategories": [subcategory2["id"]]}, headers=headers)
95+
assert update_response.status_code == 201
96+
97+
assert self._category_subcategory_ids(category["id"]) == sorted([subcategory1["id"], subcategory2["id"]])
98+
99+
def test_update_subcategory_adds_categories_and_products(self, create_authenticated_headers, create_category, create_product, create_subcategory):
100+
category1 = create_category("UC1").get_json()
101+
category2 = create_category("UC2").get_json()
102+
product1 = create_product("UP1").get_json()
103+
product2 = create_product("UP2").get_json()
104+
subcategory = create_subcategory("U_SC").get_json()
105+
106+
headers = create_authenticated_headers()
107+
update_response = self.client.put(
108+
f"/subcategory/{subcategory['id']}/update",
109+
json={"categories": [category1["id"], category2["id"]], "products": [product1["id"], product2["id"]]},
110+
headers=headers,
111+
)
112+
assert update_response.status_code == 201
113+
114+
assert self._subcategory_category_ids(subcategory["id"]) == sorted([category1["id"], category2["id"]])
115+
assert self._subcategory_product_ids(subcategory["id"]) == sorted([product1["id"], product2["id"]])
116+
117+
def test_update_product_adds_subcategories(self, create_authenticated_headers, create_product, create_subcategory):
118+
subcategory1 = create_subcategory("UPS1").get_json()
119+
subcategory2 = create_subcategory("UPS2").get_json()
120+
product = create_product("UP", "desc", subcategories=[subcategory1["id"]]).get_json()
121+
122+
headers = create_authenticated_headers()
123+
update_response = self.client.put(f"/product/{product['id']}/update", json={"subcategories": [subcategory2["id"]]}, headers=headers)
124+
assert update_response.status_code == 201
125+
126+
assert self._product_subcategory_ids(product["id"]) == sorted([subcategory1["id"], subcategory2["id"]])
127+
128+
def test_get_category_subcategories_empty(self, create_category):
129+
category = create_category("Cat_NoSC").get_json()
130+
resp = self.client.get(f"/category/{category['id']}/subcategories")
131+
self._assert_related_collection(resp, "subcategories")
132+
133+
def test_get_category_subcategories_populated(self, create_category, create_subcategory):
134+
subcategory1 = create_subcategory("SC1").get_json()
135+
subcategory2 = create_subcategory("SC2").get_json()
136+
category = create_category("Cat_WithSC", subcategories=[subcategory1["id"], subcategory2["id"]]).get_json()
137+
138+
resp = self.client.get(f"/category/{category['id']}/subcategories")
139+
self._assert_related_collection(resp, "subcategories", expected_ids=[subcategory1["id"], subcategory2["id"]])
140+
141+
def test_get_category_products_empty(self, create_category):
142+
category = create_category("Cat_NoProd").get_json()
143+
resp = self.client.get(f"/category/{category['id']}/products")
144+
self._assert_related_collection(resp, "products")
145+
146+
def test_get_category_products_populated_with_pagination(self, create_category, create_subcategory, create_product):
147+
category = create_category("Cat_Prod").get_json()
148+
subcategory = create_subcategory("SC_Prod", categories=[category["id"]]).get_json()
149+
150+
product_ids = set()
151+
for index in range(12):
152+
product_resp = create_product(f"P{index}", "desc", subcategories=[subcategory["id"]])
153+
product_ids.add(product_resp.get_json().get("id"))
154+
155+
page1 = self.client.get(f"/category/{category['id']}/products?page=1").get_json()
156+
page2 = self.client.get(f"/category/{category['id']}/products?page=2").get_json()
157+
assert len(page1["products"]) == 10
158+
assert len(page2["products"]) == 2
159+
160+
returned_product_ids = set(p["id"] for p in page1["products"] + page2["products"])
161+
assert returned_product_ids == product_ids
162+
163+
def test_get_subcategory_categories_empty(self, create_subcategory):
164+
subcategory = create_subcategory("SC_NoCat").get_json()
165+
resp = self.client.get(f"/subcategory/{subcategory['id']}/categories")
166+
self._assert_related_collection(resp, "categories")
167+
168+
def test_get_subcategory_categories_populated(self, create_category, create_subcategory):
169+
category1 = create_category("C1").get_json()
170+
category2 = create_category("C2").get_json()
171+
subcategory = create_subcategory("SC_Cats", categories=[category1["id"], category2["id"]]).get_json()
172+
173+
resp = self.client.get(f"/subcategory/{subcategory['id']}/categories")
174+
self._assert_related_collection(resp, "categories", expected_ids=[category1["id"], category2["id"]])
175+
176+
def test_get_subcategory_products_empty(self, create_subcategory):
177+
subcategory = create_subcategory("SC_NoProd").get_json()
178+
resp = self.client.get(f"/subcategory/{subcategory['id']}/products")
179+
self._assert_related_collection(resp, "products")
180+
181+
def test_get_subcategory_products_populated_with_pagination(self, create_subcategory, create_product):
182+
subcategory = create_subcategory("SC_Pag").get_json()
183+
184+
product_ids = set()
185+
for index in range(11):
186+
product_resp = create_product(f"SP{index}", "desc", subcategories=[subcategory["id"]])
187+
product_ids.add(product_resp.get_json().get("id"))
188+
189+
page1 = self.client.get(f"/subcategory/{subcategory['id']}/products?page=1").get_json()
190+
page2 = self.client.get(f"/subcategory/{subcategory['id']}/products?page=2").get_json()
191+
assert len(page1["products"]) == 10
192+
assert len(page2["products"]) == 1
193+
194+
returned_product_ids = set(p["id"] for p in page1["products"] + page2["products"])
195+
assert returned_product_ids == product_ids
196+
197+
def test_get_product_subcategories_empty(self, create_product):
198+
product = create_product("Prod_NoSC", "desc").get_json()
199+
resp = self.client.get(f"/product/{product['id']}/subcategories")
200+
self._assert_related_collection(resp, "subcategories")
201+
202+
def test_get_product_subcategories_populated(self, create_product, create_subcategory):
203+
subcategory1 = create_subcategory("S1").get_json()
204+
subcategory2 = create_subcategory("S2").get_json()
205+
product = create_product("Prod_SC", "desc", subcategories=[subcategory1["id"], subcategory2["id"]]).get_json()
206+
207+
resp = self.client.get(f"/product/{product['id']}/subcategories")
208+
self._assert_related_collection(resp, "subcategories", expected_ids=[subcategory1["id"], subcategory2["id"]])
209+
210+
@pytest.mark.parametrize(
211+
"path",
212+
[
213+
"/category/999999/subcategories",
214+
"/category/999999/products",
215+
"/subcategory/999999/categories",
216+
"/subcategory/999999/products",
217+
"/product/999999/subcategories",
218+
],
219+
)
220+
def test_relationship_getters_404(self, path):
221+
resp = self.client.get(path)
222+
assert resp.status_code == 404

tests/test_subcategory.py

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,6 @@ def setup(self, client):
1313
with client.application.app_context():
1414
assert Subcategory.query.count() == 0
1515

16-
@pytest.fixture
17-
def create_subcategory(self, create_authenticated_headers):
18-
def _create(name, categories=None, products=None, headers=None):
19-
if headers is None:
20-
headers = create_authenticated_headers()
21-
payload = {"name": name}
22-
if categories is not None:
23-
payload["categories"] = categories
24-
if products is not None:
25-
payload["products"] = products
26-
return self.client.post(
27-
"/subcategory/create", json=payload, headers=headers
28-
)
29-
return _create
30-
3116
def _count_subcategories(self):
3217
with self.client.application.app_context():
3318
return Subcategory.query.count()
@@ -59,8 +44,6 @@ def test_create_subcategory_duplicate_name(self, create_subcategory):
5944
assert self._count_subcategories() == 1
6045
self._verify_subcategory_in_db(self.TEST_SUBCATEGORY_NAME)
6146

62-
# TODO: Add tests for creation with categories and products when those fixtures/utilities are available
63-
6447
def test_get_subcategory_by_id(self, create_subcategory):
6548
response = create_subcategory("Laptops")
6649
data = response.get_json()
@@ -173,27 +156,3 @@ def test_delete_subcategory_token_error(self, get_headers, create_subcategory, c
173156

174157
utils.verify_token_error_response(delete_resp, expected_code)
175158
self._verify_subcategory_in_db("DeleteTokenError")
176-
177-
def test_get_subcategory_categories_empty(self, create_subcategory):
178-
response = create_subcategory("NoCatRel")
179-
data = response.get_json()
180-
sc_id = data["id"]
181-
182-
resp = self.client.get(f"/subcategory/{sc_id}/categories")
183-
184-
assert resp.status_code == 200
185-
data = resp.get_json()
186-
assert "categories" in data
187-
assert data["categories"] == []
188-
189-
def test_get_subcategory_products_empty(self, create_subcategory):
190-
response = create_subcategory("NoProdRel")
191-
data = response.get_json()
192-
sc_id = data["id"]
193-
194-
resp = self.client.get(f"/subcategory/{sc_id}/products")
195-
196-
assert resp.status_code == 200
197-
data = resp.get_json()
198-
assert "products" in data
199-
assert data["products"] == []

0 commit comments

Comments
 (0)