Skip to content

Commit 97bb4ab

Browse files
committed
Fix test reliability issues:
- Remove global config loading from test files - Use base_url fixture consistently - Add proper error handling for test data loading - Add better error messages and context - Add request timeouts - Add detailed error reporting for schema validation - Add comprehensive test data validation - Add better Allure attachments for debugging These changes improve test reliability and debugging by: 1. Preventing configuration loading race conditions 2. Adding proper error context for failures 3. Improving error handling and reporting 4. Making test data loading more robust
1 parent 4547262 commit 97bb4ab

3 files changed

Lines changed: 140 additions & 70 deletions

File tree

tests/test_api_validation.py

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@
88
import pytest
99
import requests
1010
import allure
11+
import json
1112
from jsonschema import validate
12-
from utils.api_utils import load_config, load_schema, get_headers
13-
14-
# Load base configuration from config.yaml
15-
config = load_config()
16-
BASE_URL = config["environments"][config["env"]]["base_url"]
13+
from utils.api_utils import load_schema, get_headers
1714

1815

1916
@pytest.mark.api_validation
@@ -22,37 +19,51 @@
2219
@allure.feature("Response Headers")
2320
@allure.title("Validate Standard Headers")
2421
@allure.severity(allure.severity_level.TRIVIAL)
25-
def test_headers_validation():
22+
def test_headers_validation(base_url):
2623
"""
2724
Test that standard headers are present and correct in the API response.
2825
Validates content type, encoding, and other standard HTTP headers.
2926
"""
3027
with allure.step("Send GET request to users endpoint"):
31-
url = f"{BASE_URL}/users?page=1"
32-
response = requests.get(url, headers=get_headers())
28+
try:
29+
url = f"{base_url}/users?page=1"
30+
response = requests.get(url, headers=get_headers(), timeout=10)
31+
except requests.exceptions.RequestException as e:
32+
allure.attach(str(e), "Request Error", allure.attachment_type.TEXT)
33+
raise
3334

3435
with allure.step("Verify response status is 200"):
35-
assert response.status_code == 200
36+
assert response.status_code == 200, (
37+
f"Expected status 200, got {response.status_code}. "
38+
f"Response: {response.text}"
39+
)
3640

3741
with allure.step("Validate Content-Type header"):
38-
assert response.headers["Content-Type"].startswith("application/json")
42+
content_type = response.headers.get("Content-Type", "")
43+
assert content_type.startswith("application/json"), (
44+
f"Expected application/json Content-Type, got: {content_type}"
45+
)
3946

4047
with allure.step("Validate response headers are present"):
48+
headers = dict(response.headers)
49+
allure.attach(
50+
json.dumps(headers, indent=2),
51+
"Response Headers",
52+
allure.attachment_type.JSON
53+
)
54+
4155
# Check for Content-Type (always present)
42-
assert "Content-Type" in response.headers
56+
assert "Content-Type" in headers, "Missing Content-Type header"
4357

4458
# Check for either Content-Length or Transfer-Encoding (both are valid)
45-
has_content_length = "Content-Length" in response.headers
46-
has_transfer_encoding = "Transfer-Encoding" in response.headers
47-
assert has_content_length or has_transfer_encoding, \
48-
"Either Content-Length or Transfer-Encoding should be present"
59+
has_content_length = "Content-Length" in headers
60+
has_transfer_encoding = "Transfer-Encoding" in headers
61+
assert has_content_length or has_transfer_encoding, (
62+
"Missing both Content-Length and Transfer-Encoding headers"
63+
)
4964

5065
# Validate Date header is present
51-
assert "Date" in response.headers
52-
53-
with allure.step("Attach headers to report"):
54-
headers_info = dict(response.headers)
55-
allure.attach(str(headers_info), "Response Headers", allure.attachment_type.TEXT)
66+
assert "Date" in headers, "Missing Date header"
5667

5768

5869
@pytest.mark.api_validation
@@ -61,13 +72,13 @@ def test_headers_validation():
6172
@allure.feature("Schema Validation")
6273
@allure.title("Validate User List Schema Compliance")
6374
@allure.severity(allure.severity_level.CRITICAL)
64-
def test_user_list_schema_validation():
75+
def test_user_list_schema_validation(base_url):
6576
"""
6677
Comprehensive schema validation for user list endpoint.
6778
Ensures all required fields and data types are correct.
6879
"""
6980
with allure.step("Send GET request to user list endpoint"):
70-
url = f"{BASE_URL}/users?page=1"
81+
url = f"{base_url}/users?page=1"
7182
response = requests.get(url, headers=get_headers())
7283

7384
with allure.step("Verify response status is 200"):
@@ -107,13 +118,13 @@ def test_user_list_schema_validation():
107118
@allure.feature("Schema Validation")
108119
@allure.title("Validate Single User Schema Compliance")
109120
@allure.severity(allure.severity_level.CRITICAL)
110-
def test_single_user_schema_validation():
121+
def test_single_user_schema_validation(base_url):
111122
"""
112123
Comprehensive schema validation for single user endpoint.
113124
Ensures response structure matches expected contract.
114125
"""
115126
with allure.step("Send GET request to single user endpoint"):
116-
url = f"{BASE_URL}/users/2"
127+
url = f"{base_url}/users/2"
117128
response = requests.get(url, headers=get_headers())
118129

119130
with allure.step("Verify response status is 200"):
@@ -150,13 +161,13 @@ def test_single_user_schema_validation():
150161
@allure.title("Validate Response Time Performance")
151162
@allure.severity(allure.severity_level.NORMAL)
152163
@pytest.mark.parametrize("endpoint", ["/users?page=1", "/users/1"])
153-
def test_response_time_validation(endpoint):
164+
def test_response_time_validation(endpoint, base_url):
154165
"""
155166
Test that API responses are returned within acceptable time limits.
156167
Validates performance requirements.
157168
"""
158169
with allure.step(f"Send GET request to {endpoint}"):
159-
url = f"{BASE_URL}{endpoint}"
170+
url = f"{base_url}{endpoint}"
160171
response = requests.get(url, headers=get_headers())
161172

162173
with allure.step("Verify response status is 200"):

tests/test_error_scenarios.py

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@
88
import pytest
99
import requests
1010
import allure
11-
from utils.api_utils import load_config, get_headers
12-
13-
# Load base configuration from config.yaml
14-
config = load_config()
15-
BASE_URL = config["environments"][config["env"]]["base_url"]
11+
import json
12+
from utils.api_utils import get_headers
1613

1714

1815
@pytest.mark.error_scenarios
@@ -21,25 +18,37 @@
2118
@allure.feature("User Retrieval Errors")
2219
@allure.title("GET Non-Existent User")
2320
@allure.severity(allure.severity_level.MINOR)
24-
def test_get_user_not_found():
21+
def test_get_user_not_found(base_url):
2522
"""
2623
Test retrieving a non-existent user.
2724
Expects a 404 Not Found response.
2825
"""
2926
with allure.step("Send GET request for non-existent user"):
30-
url = f"{BASE_URL}/users/9999"
31-
response = requests.get(url, headers=get_headers())
27+
url = f"{base_url}/users/9999"
28+
response = requests.get(url, headers=get_headers(), timeout=10)
3229

3330
with allure.step("Verify response status is 404"):
34-
assert response.status_code == 404
31+
assert response.status_code == 404, (
32+
f"Expected status 404, got {response.status_code}. "
33+
f"Response: {response.text}"
34+
)
3535

3636
with allure.step("Verify response body is empty or contains error info"):
37-
# ReqRes API returns empty object for 404
38-
data = response.json()
39-
assert data == {}
37+
try:
38+
data = response.json()
39+
assert data == {}, f"Expected empty object, got: {json.dumps(data, indent=2)}"
40+
except json.JSONDecodeError as e:
41+
allure.attach(response.text, "Invalid JSON Response", allure.attachment_type.TEXT)
42+
allure.attach(str(e), "JSON Parse Error", allure.attachment_type.TEXT)
43+
raise
4044

4145
with allure.step("Attach response details to report"):
4246
allure.attach(response.text, "404 Response Body", allure.attachment_type.JSON)
47+
allure.attach(
48+
json.dumps(get_headers(), indent=2),
49+
"Request Headers",
50+
allure.attachment_type.JSON
51+
)
4352

4453

4554
@pytest.mark.error_scenarios
@@ -49,13 +58,13 @@ def test_get_user_not_found():
4958
@allure.title("GET User with Invalid ID Format")
5059
@allure.severity(allure.severity_level.MINOR)
5160
@pytest.mark.parametrize("invalid_id", ["abc", "!@#", "0", "-1"])
52-
def test_get_user_invalid_id(invalid_id):
61+
def test_get_user_invalid_id(invalid_id, base_url):
5362
"""
5463
Test retrieving a user with invalid ID formats.
5564
Validates error handling for malformed requests.
5665
"""
5766
with allure.step(f"Send GET request with invalid ID: {invalid_id}"):
58-
url = f"{BASE_URL}/users/{invalid_id}"
67+
url = f"{base_url}/users/{invalid_id}"
5968
response = requests.get(url, headers=get_headers())
6069

6170
with allure.step("Verify response indicates error or not found"):
@@ -72,13 +81,13 @@ def test_get_user_invalid_id(invalid_id):
7281
@allure.feature("User Creation Errors")
7382
@allure.title("POST User with Empty Payload")
7483
@allure.severity(allure.severity_level.NORMAL)
75-
def test_create_user_empty_payload():
84+
def test_create_user_empty_payload(base_url):
7685
"""
7786
Test creating a user with empty payload.
7887
Validates API behavior with missing data.
7988
"""
8089
with allure.step("Send POST request with empty payload"):
81-
url = f"{BASE_URL}/users"
90+
url = f"{base_url}/users"
8291
response = requests.post(url, json={}, headers=get_headers())
8392

8493
with allure.step("Verify response (API may accept empty payload)"):
@@ -101,13 +110,13 @@ def test_create_user_empty_payload():
101110
@allure.feature("User Creation Errors")
102111
@allure.title("POST User with Invalid JSON")
103112
@allure.severity(allure.severity_level.NORMAL)
104-
def test_create_user_invalid_json():
113+
def test_create_user_invalid_json(base_url):
105114
"""
106115
Test creating a user with malformed JSON.
107116
Validates API error handling for invalid request format.
108117
"""
109118
with allure.step("Send POST request with invalid JSON"):
110-
url = f"{BASE_URL}/users"
119+
url = f"{base_url}/users"
111120
headers = get_headers()
112121
# Send malformed JSON as string
113122
response = requests.post(url, data='{"name": "test", "job":}', headers=headers)
@@ -126,13 +135,13 @@ def test_create_user_invalid_json():
126135
@allure.feature("Invalid Endpoints")
127136
@allure.title("GET Invalid Endpoint")
128137
@allure.severity(allure.severity_level.MINOR)
129-
def test_invalid_endpoint():
138+
def test_invalid_endpoint(base_url):
130139
"""
131140
Test accessing an invalid/non-existent endpoint.
132141
ReqRes API may handle invalid endpoints differently than expected.
133142
"""
134143
with allure.step("Send GET request to invalid endpoint"):
135-
url = f"{BASE_URL}/invalid-endpoint"
144+
url = f"{base_url}/invalid-endpoint"
136145
response = requests.get(url, headers=get_headers())
137146

138147
with allure.step("Document API behavior for invalid endpoints"):
@@ -160,14 +169,14 @@ def test_invalid_endpoint():
160169
@allure.feature("Invalid Endpoints")
161170
@allure.title("GET Non-existent User ID")
162171
@allure.severity(allure.severity_level.MINOR)
163-
def test_malformed_url():
172+
def test_malformed_url(base_url):
164173
"""
165174
Test accessing a user with an ID that definitely doesn't exist.
166175
ReqRes API returns 404 for non-existent user IDs.
167176
"""
168177
with allure.step("Send GET request to non-existent user ID"):
169178
# Use a very high user ID that definitely doesn't exist
170-
url = f"{BASE_URL}/users/999999"
179+
url = f"{base_url}/users/999999"
171180
response = requests.get(url, headers=get_headers())
172181

173182
with allure.step("Verify response indicates not found"):

0 commit comments

Comments
 (0)