diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md
index ad81f49..cf70246 100644
--- a/docs/DEVELOPMENT.md
+++ b/docs/DEVELOPMENT.md
@@ -195,15 +195,82 @@ All resource mocks are in the root [conftest.py](tests/conftest.py).
### Response Mocking
-The test suite uses consistent patterns for mocking API responses:
+The test suite uses the `mock_response_factory` fixture from `tests/conftest.py`
+to create consistent, configurable mock responses. This is the required pattern
+for all tests that need to mock HTTP responses.
+
+#### Standard Mock Response Pattern
+
+```python
+def test_some_endpoint(resource, mock_oauth_session, mock_response_factory):
+ """Test description."""
+ # Define expected data first
+ expected_data = {"data": "test"}
+
+ # Create mock response using the factory
+ mock_response = mock_response_factory(200, expected_data)
+
+ # Assign to oauth.request.return_value
+ resource.oauth.request.return_value = mock_response
+
+ # Call the method under test
+ result = resource.some_method()
+
+ # Assert against expected_data, not mock_response.json.return_value
+ assert result == expected_data
+```
+
+#### Response Factory Examples
```python
-mock_response = Mock()
-mock_response.json.return_value = {"data": "test"}
-mock_response.headers = {"content-type": "application/json"}
-mock_response.status_code = 200
+# Success response with data
+mock_response = mock_response_factory(200, {"data": "test"})
+
+# Response with custom headers
+mock_response = mock_response_factory(
+ status_code=200,
+ json_data={"data": "test"},
+ headers={"custom-header": "value"}
+)
+
+# Delete/no content response (204)
+mock_response = mock_response_factory(204)
+
+# Error response
+mock_response = mock_response_factory(
+ 400,
+ {"errors": [{"errorType": "validation", "message": "Error message"}]}
+)
+
+# Non-JSON response (XML)
+mock_response = mock_response_factory(
+ 200,
+ headers={"content-type": "application/vnd.garmin.tcx+xml"},
+ content_type="application/vnd.garmin.tcx+xml"
+)
+mock_response.text = "content"
```
+#### Parameter Validation Pattern
+
+For tests that only need to verify parameter validation or endpoint construction
+(not response handling), it's acceptable to use the following alternative
+pattern:
+
+```python
+def test_validation(resource):
+ """Test parameter validation."""
+ resource._make_request = Mock()
+ resource.some_method(param="value")
+ resource._make_request.assert_called_once_with(
+ "endpoint/path", params={"param": "value"}, user_id="-", debug=False
+ )
+```
+
+This approach provides a clean, standardized way to create mock responses with
+the desired status code, data, and headers. All test files must use one of these
+patterns.
+
## OAuth Callback Implementation
The OAuth callback mechanism is implemented using two main classes:
diff --git a/standardize_mock_responses.py b/standardize_mock_responses.py
new file mode 100755
index 0000000..bea45bd
--- /dev/null
+++ b/standardize_mock_responses.py
@@ -0,0 +1,234 @@
+#!/usr/bin/env python3
+"""
+Script to standardize mock_response usage in test files.
+
+This script finds test files that use direct mock_response manipulation and
+converts them to use mock_response_factory instead.
+"""
+
+# Standard library imports
+import os
+from pathlib import Path
+import re
+import sys
+from typing import List
+from typing import Tuple
+
+
+def find_pattern_in_file(file_path: str, pattern: str) -> List[str]:
+ """Find all matches of pattern in the given file."""
+ with open(file_path, "r") as f:
+ content = f.read()
+ return re.findall(pattern, content, re.MULTILINE)
+
+
+def transform_file(file_path: str, dry_run: bool = False) -> bool:
+ """Transform a file to use mock_response_factory."""
+ with open(file_path, "r") as f:
+ content = f.read()
+
+ # Backup original content
+ original_content = content
+
+ # Pattern 1: def test_*(mock_response) -> def test_*(mock_response_factory)
+ # Find all test function definitions
+ test_pattern = r"(def\s+test_\w+\([^)]*)(,\s*mock_response)(\s*[,)].*)"
+
+ def param_replacement(match):
+ before = match.group(1)
+ param = match.group(2).replace("mock_response", "mock_response_factory")
+ after = match.group(3)
+ return f"{before}{param}{after}"
+
+ content = re.sub(test_pattern, param_replacement, content)
+
+ # Pattern 2: mock_response.json.return_value = {...}
+ pattern2 = r"([ \t]*)mock_response\.json\.return_value\s*=\s*({[^;]*}|\[[^;]*\])"
+
+ def replacement2(match):
+ indent = match.group(1)
+ data = match.group(2).strip()
+ # Ensure data has balanced braces
+ open_braces = data.count("{") - data.count("}")
+ open_brackets = data.count("[") - data.count("]")
+
+ if open_braces != 0 or open_brackets != 0:
+ # Skip this match as it has unbalanced braces or brackets
+ return match.group(0)
+
+ return f"{indent}mock_response = mock_response_factory(\n{indent} 200, \n{indent} {data}\n{indent})"
+
+ content = re.sub(pattern2, replacement2, content)
+
+ # Pattern 3: mock_response.status_code = 204
+ pattern3 = r"([ \t]*)mock_response\.status_code\s*=\s*(\d+)"
+
+ def replacement3(match):
+ indent = match.group(1)
+ status_code = match.group(2)
+ return f"{indent}mock_response = mock_response_factory({status_code})"
+
+ content = re.sub(pattern3, replacement3, content)
+
+ # Pattern 4: We're disabling this pattern for now as it was causing issues
+ # The goal was to change order of assignments (response assignment should come before oauth assignment)
+ # but it was causing syntax errors
+ """
+ pattern4 = r'([ \t]*)(.*?)\.oauth(?:\.|\w+\.)*request\.return_value\s*=\s*mock_response\n([ \t]*)mock_response\s*=\s*mock_response_factory'
+
+ def replacement4(match):
+ indent1 = match.group(1)
+ obj = match.group(2)
+ indent2 = match.group(3)
+ return f"{indent2}mock_response = mock_response_factory\n{indent1}{obj}.oauth.request.return_value = mock_response"
+
+ content = re.sub(pattern4, replacement4, content)
+ """
+
+ # Pattern 5: Fix cases where test was updated to use mock_response_factory as parameter
+ # but still uses mock_response in the body
+ pattern5 = r"def\s+test_\w+\([^)]*mock_response_factory[^)]*\).*?(?=\n\s*def|\Z)"
+
+ def fix_mock_response_usage(match):
+ test_func = match.group(0)
+ # If the function uses mock_response_factory but also has direct mock_response usage
+ if (
+ "mock_response.json.return_value =" in test_func
+ or "mock_response.status_code =" in test_func
+ ):
+ # Add a mock_response declaration at the beginning of the function body
+ # Find the first indented line after the function def
+ lines = test_func.split("\n")
+ for i, line in enumerate(lines):
+ if i > 0 and line.strip() and not line.strip().startswith("#"):
+ indent = re.match(r"(\s*)", line).group(1)
+ # Insert the mock_response assignment after docstring (if any)
+ for j in range(i, len(lines)):
+ if not lines[j].strip().startswith('"""') and not lines[
+ j
+ ].strip().startswith("'''"):
+ lines.insert(j, f"{indent}mock_response = mock_response_factory(200)")
+ break
+ break
+ return "\n".join(lines)
+ return test_func
+
+ content = re.sub(pattern5, fix_mock_response_usage, content, flags=re.DOTALL)
+
+ # Pattern 6: Replace assert result == mock_response.json.return_value with assert result == expected_data
+ pattern6 = r"([ \t]*assert\s+.*?==\s*)mock_response\.json\.return_value"
+
+ def fix_assertions(match):
+ before_part = match.group(1)
+ return f"{before_part}mock_response.json()"
+
+ content = re.sub(pattern6, fix_assertions, content)
+
+ # If no changes were made, return False
+ if content == original_content:
+ return False
+
+ # Write the changes back to the file
+ if not dry_run:
+ with open(file_path, "w") as f:
+ f.write(content)
+
+ return True
+
+
+def find_files_to_transform() -> List[Tuple[str, bool]]:
+ """Find all test files that need to be transformed."""
+ test_dir = Path("tests")
+ # Allow specifying a subdirectory
+ if len(sys.argv) > 1 and not sys.argv[1].startswith("--"):
+ test_dir = Path(sys.argv[1])
+ print(f"Searching in directory: {test_dir}")
+
+ result = []
+ verbose = "--verbose" in sys.argv
+
+ for root, _, files in os.walk(test_dir):
+ for file in files:
+ if file.endswith(".py") and file.startswith("test_"):
+ file_path = os.path.join(root, file)
+
+ # First check for any mention of mock_response
+ has_mock_response = bool(find_pattern_in_file(file_path, r"mock_response"))
+
+ if not has_mock_response:
+ continue
+
+ # More detailed patterns
+ # Check if file uses mock_response directly as parameter
+ uses_mock_response = bool(
+ find_pattern_in_file(
+ file_path, r"def\s+test_\w+\([^)]*,\s*mock_response\s*[,)]"
+ )
+ )
+
+ # Check if file directly manipulates mock_response
+ manipulates_mock_response = bool(
+ find_pattern_in_file(
+ file_path, r"mock_response\.(json\.return_value|status_code)\s*="
+ )
+ )
+
+ # Check if file uses mock_response.json.return_value in assertions
+ uses_return_value_in_assertions = bool(
+ find_pattern_in_file(
+ file_path, r"assert\s+.*?=.*?mock_response\.json\.return_value"
+ )
+ )
+
+ # Check if file uses mock_response_factory
+ uses_factory = bool(
+ find_pattern_in_file(file_path, r"mock_response\s*=\s*mock_response_factory")
+ )
+
+ # Determine if file needs transformation
+ needs_transform = (
+ uses_mock_response or manipulates_mock_response
+ ) and not uses_factory
+
+ # Also flag files that use factory but still use mock_response.json.return_value in assertions
+ if uses_factory and uses_return_value_in_assertions and not needs_transform:
+ needs_transform = True
+
+ if verbose or needs_transform:
+ print(f"File: {file_path}")
+ print(f" Has mock_response: {has_mock_response}")
+ print(f" Uses as parameter: {uses_mock_response}")
+ print(f" Manipulates: {manipulates_mock_response}")
+ print(f" Uses in assertions: {uses_return_value_in_assertions}")
+ print(f" Uses factory: {uses_factory}")
+ print(f" Needs transform: {needs_transform}")
+
+ if needs_transform:
+ result.append((file_path, needs_transform))
+
+ return result
+
+
+def main():
+ """Main entry point."""
+ dry_run = "--dry-run" in sys.argv
+ files = find_files_to_transform()
+
+ print(f"Found {len(files)} files that need to be transformed.")
+ if dry_run:
+ print("Running in dry-run mode. No files will be modified.")
+
+ for file_path, _ in files:
+ print(f"Transforming {file_path}...", end="")
+ transformed = transform_file(file_path, dry_run)
+ print(" TRANSFORMED" if transformed else " SKIPPED (no changes)")
+
+ print("\nDone!")
+ print(f"Transformed {len(files)} files.")
+
+ if dry_run:
+ print("\nRun without --dry-run to apply changes.")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries.py b/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries.py
index 4548cce..b043c24 100644
--- a/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries.py
+++ b/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries.py
@@ -3,12 +3,13 @@
"""Tests for the get_azm_timeseries endpoint."""
-def test_get_azm_timeseries_with_today_date(azm_resource, mock_response):
+def test_get_azm_timeseries_with_today_date(azm_resource, mock_response_factory):
"""Test using 'today' as the date parameter"""
- mock_response.json.return_value = {"activities-active-zone-minutes": []}
+ expected_data = {"activities-active-zone-minutes": []}
+ mock_response = mock_response_factory(200, expected_data)
azm_resource.oauth.request.return_value = mock_response
result = azm_resource.get_azm_timeseries_by_date(date="today")
- assert result == mock_response.json.return_value
+ assert result == expected_data
azm_resource.oauth.request.assert_called_once_with(
"GET",
"https://api.fitbit.com/1/user/-/activities/active-zone-minutes/date/today/1d.json",
diff --git a/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries_by_date.py b/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries_by_date.py
index 6882d6f..c55804f 100644
--- a/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries_by_date.py
+++ b/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries_by_date.py
@@ -13,9 +13,9 @@
from fitbit_client.resources._constants import Period
-def test_get_azm_timeseries_by_date_success(azm_resource, mock_response):
+def test_get_azm_timeseries_by_date_success(azm_resource, mock_response_factory):
"""Test successful retrieval of AZM time series by date with default period"""
- mock_response.json.return_value = {
+ expected_data = {
"activities-active-zone-minutes": [
{
"dateTime": "2025-02-01",
@@ -28,9 +28,10 @@ def test_get_azm_timeseries_by_date_success(azm_resource, mock_response):
}
]
}
+ mock_response = mock_response_factory(200, expected_data)
azm_resource.oauth.request.return_value = mock_response
result = azm_resource.get_azm_timeseries_by_date(date="2025-02-01")
- assert result == mock_response.json.return_value
+ assert result == expected_data
azm_resource.oauth.request.assert_called_once_with(
"GET",
"https://api.fitbit.com/1/user/-/activities/active-zone-minutes/date/2025-02-01/1d.json",
@@ -41,12 +42,13 @@ def test_get_azm_timeseries_by_date_success(azm_resource, mock_response):
)
-def test_get_azm_timeseries_by_date_explicit_period(azm_resource, mock_response):
+def test_get_azm_timeseries_by_date_explicit_period(azm_resource, mock_response_factory):
"""Test successful retrieval of AZM time series by date with explicit ONE_DAY period"""
- mock_response.json.return_value = {"activities-active-zone-minutes": []}
+ expected_data = {"activities-active-zone-minutes": []}
+ mock_response = mock_response_factory(200, expected_data)
azm_resource.oauth.request.return_value = mock_response
result = azm_resource.get_azm_timeseries_by_date(date="2025-02-01", period=Period.ONE_DAY)
- assert result == mock_response.json.return_value
+ assert result == expected_data
azm_resource.oauth.request.assert_called_once_with(
"GET",
"https://api.fitbit.com/1/user/-/activities/active-zone-minutes/date/2025-02-01/1d.json",
@@ -57,12 +59,13 @@ def test_get_azm_timeseries_by_date_explicit_period(azm_resource, mock_response)
)
-def test_get_azm_timeseries_by_date_with_user_id(azm_resource, mock_response):
+def test_get_azm_timeseries_by_date_with_user_id(azm_resource, mock_response_factory):
"""Test getting AZM time series for a specific user"""
- mock_response.json.return_value = {"activities-active-zone-minutes": []}
+ expected_data = {"activities-active-zone-minutes": []}
+ mock_response = mock_response_factory(200, expected_data)
azm_resource.oauth.request.return_value = mock_response
result = azm_resource.get_azm_timeseries_by_date(date="2025-02-01", user_id="123ABC")
- assert result == mock_response.json.return_value
+ assert result == expected_data
azm_resource.oauth.request.assert_called_once_with(
"GET",
"https://api.fitbit.com/1/user/123ABC/activities/active-zone-minutes/date/2025-02-01/1d.json",
diff --git a/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries_by_interval.py b/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries_by_interval.py
index 1d97f67..7f89b25 100644
--- a/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries_by_interval.py
+++ b/tests/fitbit_client/resources/active_zone_minutes/test_get_azm_timeseries_by_interval.py
@@ -16,9 +16,9 @@
from fitbit_client.exceptions import InvalidDateRangeException
-def test_get_azm_timeseries_by_interval_success(azm_resource, mock_response):
+def test_get_azm_timeseries_by_interval_success(azm_resource, mock_response_factory):
"""Test successful retrieval of AZM time series by date range"""
- mock_response.json.return_value = {
+ expected_data = {
"activities-active-zone-minutes": [
{
"dateTime": "2025-02-01",
@@ -39,11 +39,12 @@ def test_get_azm_timeseries_by_interval_success(azm_resource, mock_response):
},
]
}
+ mock_response = mock_response_factory(200, expected_data)
azm_resource.oauth.request.return_value = mock_response
result = azm_resource.get_azm_timeseries_by_interval(
start_date="2025-02-01", end_date="2025-02-02"
)
- assert result == mock_response.json.return_value
+ assert result == expected_data
azm_resource.oauth.request.assert_called_once_with(
"GET",
"https://api.fitbit.com/1/user/-/activities/active-zone-minutes/date/2025-02-01/2025-02-02.json",
@@ -54,14 +55,15 @@ def test_get_azm_timeseries_by_interval_success(azm_resource, mock_response):
)
-def test_get_azm_timeseries_by_interval_with_user_id(azm_resource, mock_response):
+def test_get_azm_timeseries_by_interval_with_user_id(azm_resource, mock_response_factory):
"""Test getting AZM time series by date range for a specific user"""
- mock_response.json.return_value = {"activities-active-zone-minutes": []}
+ expected_data = {"activities-active-zone-minutes": []}
+ mock_response = mock_response_factory(200, expected_data)
azm_resource.oauth.request.return_value = mock_response
result = azm_resource.get_azm_timeseries_by_interval(
start_date="2025-02-01", end_date="2025-02-02", user_id="123ABC"
)
- assert result == mock_response.json.return_value
+ assert result == expected_data
azm_resource.oauth.request.assert_called_once_with(
"GET",
"https://api.fitbit.com/1/user/123ABC/activities/active-zone-minutes/date/2025-02-01/2025-02-02.json",
diff --git a/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries.py b/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries.py
index 9995eba..e89181c 100644
--- a/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries.py
+++ b/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries.py
@@ -9,9 +9,11 @@
from fitbit_client.resources._constants import Period
-def test_get_activity_timeseries_with_today_date(activity_timeseries_resource, mock_response):
+def test_get_activity_timeseries_with_today_date(
+ activity_timeseries_resource, mock_response_factory
+):
"""Test using 'today' as the date parameter"""
- mock_response.json.return_value = {"activities-steps": []}
+ mock_response = mock_response_factory(200, {"activities-steps": []})
activity_timeseries_resource.oauth.request.return_value = mock_response
activity_timeseries_resource.get_activity_timeseries_by_date(
resource_path=ActivityTimeSeriesPath.STEPS, date="today", period=Period.ONE_DAY
@@ -26,9 +28,11 @@ def test_get_activity_timeseries_with_today_date(activity_timeseries_resource, m
)
-def test_get_activity_timeseries_different_periods(activity_timeseries_resource, mock_response):
+def test_get_activity_timeseries_different_periods(
+ activity_timeseries_resource, mock_response_factory
+):
"""Test getting time series with different period values"""
- mock_response.json.return_value = {"activities-steps": []}
+ mock_response = mock_response_factory(200, {"activities-steps": []})
activity_timeseries_resource.oauth.request.return_value = mock_response
periods = [
Period.ONE_DAY,
diff --git a/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries_by_date.py b/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries_by_date.py
index 4ad2b79..0435236 100644
--- a/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries_by_date.py
+++ b/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries_by_date.py
@@ -13,11 +13,13 @@
from fitbit_client.resources._constants import Period
-def test_get_activity_timeseries_by_date_success(activity_timeseries_resource, mock_response):
+def test_get_activity_timeseries_by_date_success(
+ activity_timeseries_resource, mock_response_factory
+):
"""Test successful retrieval of activity time series by date"""
- mock_response.json.return_value = {
- "activities-steps": [{"dateTime": "2024-02-01", "value": "10000"}]
- }
+ mock_response = mock_response_factory(
+ 200, {"activities-steps": [{"dateTime": "2024-02-01", "value": "10000"}]}
+ )
activity_timeseries_resource.oauth.request.return_value = mock_response
result = activity_timeseries_resource.get_activity_timeseries_by_date(
resource_path=ActivityTimeSeriesPath.STEPS, date="2024-02-01", period=Period.ONE_DAY
@@ -33,9 +35,11 @@ def test_get_activity_timeseries_by_date_success(activity_timeseries_resource, m
)
-def test_get_activity_timeseries_by_date_with_user_id(activity_timeseries_resource, mock_response):
+def test_get_activity_timeseries_by_date_with_user_id(
+ activity_timeseries_resource, mock_response_factory
+):
"""Test getting time series for a specific user"""
- mock_response.json.return_value = {"activities-steps": []}
+ mock_response = mock_response_factory(200, {"activities-steps": []})
activity_timeseries_resource.oauth.request.return_value = mock_response
result = activity_timeseries_resource.get_activity_timeseries_by_date(
resource_path=ActivityTimeSeriesPath.STEPS,
@@ -68,13 +72,16 @@ def test_get_activity_timeseries_by_date_invalid_date(activity_timeseries_resour
# Local imports
-def test_calories_variants(activity_timeseries_resource, mock_response):
+def test_calories_variants(activity_timeseries_resource, mock_response_factory):
"""Test different calorie measurement types return expected data"""
- mock_response.json.return_value = {
- "activities-activityCalories": [{"dateTime": "2024-02-01", "value": "300"}],
- "activities-calories": [{"dateTime": "2024-02-01", "value": "2000"}],
- "activities-caloriesBMR": [{"dateTime": "2024-02-01", "value": "1700"}],
- }
+ mock_response = mock_response_factory(
+ 200,
+ {
+ "activities-activityCalories": [{"dateTime": "2024-02-01", "value": "300"}],
+ "activities-calories": [{"dateTime": "2024-02-01", "value": "2000"}],
+ "activities-caloriesBMR": [{"dateTime": "2024-02-01", "value": "1700"}],
+ },
+ )
activity_timeseries_resource.oauth.request.return_value = mock_response
calorie_types = [
ActivityTimeSeriesPath.ACTIVITY_CALORIES,
diff --git a/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries_by_date_range.py b/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries_by_date_range.py
index b7db8a1..d55f5d1 100644
--- a/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries_by_date_range.py
+++ b/tests/fitbit_client/resources/activity_timeseries/test_get_activity_timeseries_by_date_range.py
@@ -14,14 +14,19 @@
from fitbit_client.resources._constants import ActivityTimeSeriesPath
-def test_get_activity_timeseries_by_date_range_success(activity_timeseries_resource, mock_response):
+def test_get_activity_timeseries_by_date_range_success(
+ activity_timeseries_resource, mock_response_factory
+):
"""Test successful retrieval of activity time series by date range"""
- mock_response.json.return_value = {
- "activities-steps": [
- {"dateTime": "2024-02-01", "value": "10000"},
- {"dateTime": "2024-02-02", "value": "12000"},
- ]
- }
+ mock_response = mock_response_factory(
+ 200,
+ {
+ "activities-steps": [
+ {"dateTime": "2024-02-01", "value": "10000"},
+ {"dateTime": "2024-02-02", "value": "12000"},
+ ]
+ },
+ )
activity_timeseries_resource.oauth.request.return_value = mock_response
result = activity_timeseries_resource.get_activity_timeseries_by_date_range(
resource_path=ActivityTimeSeriesPath.STEPS, start_date="2024-02-01", end_date="2024-02-02"
@@ -43,10 +48,10 @@ def test_get_activity_timeseries_by_date_range_success(activity_timeseries_resou
def test_get_activity_timeseries_by_date_range_with_user_id(
- activity_timeseries_resource, mock_response
+ activity_timeseries_resource, mock_response_factory
):
"""Test getting time series by date range for a specific user"""
- mock_response.json.return_value = {"activities-steps": []}
+ mock_response = mock_response_factory(200, {"activities-steps": []})
activity_timeseries_resource.oauth.request.return_value = mock_response
result = activity_timeseries_resource.get_activity_timeseries_by_date_range(
resource_path=ActivityTimeSeriesPath.STEPS,
diff --git a/tests/fitbit_client/resources/body_timeseries/test_get_body_timeseries_by_date.py b/tests/fitbit_client/resources/body_timeseries/test_get_body_timeseries_by_date.py
index 766ca4f..790ac44 100644
--- a/tests/fitbit_client/resources/body_timeseries/test_get_body_timeseries_by_date.py
+++ b/tests/fitbit_client/resources/body_timeseries/test_get_body_timeseries_by_date.py
@@ -54,11 +54,11 @@ def test_get_body_timeseries_by_date_period_validation(body_timeseries):
)
-def test_get_body_timeseries_by_date_successful_flow(body_timeseries, mock_response):
+def test_get_body_timeseries_by_date_successful_flow(body_timeseries, mock_response_factory):
"""Test the successful flow through validation and request for get_body_timeseries_by_date."""
# Set up the mock response
+ mock_response = mock_response_factory(200, {"expected": "response"})
body_timeseries.oauth.request.return_value = mock_response
- mock_response.json.return_value = {"expected": "response"}
# Test with BMI resource type (which allows all periods)
result = body_timeseries.get_body_timeseries_by_date(
@@ -103,11 +103,11 @@ def test_get_body_timeseries_by_date_successful_flow(body_timeseries, mock_respo
)
-def test_get_body_timeseries_by_date_makes_correct_request(body_timeseries, mock_response):
+def test_get_body_timeseries_by_date_makes_correct_request(body_timeseries, mock_response_factory):
"""Test that the correct endpoint is called with proper parameters."""
# Set up the mock response
+ mock_response = mock_response_factory(200, {"expected": "response"})
body_timeseries.oauth.request.return_value = mock_response
- mock_response.json.return_value = {"expected": "response"}
# Call the method
result = body_timeseries.get_body_timeseries_by_date(
diff --git a/tests/fitbit_client/resources/body_timeseries/test_get_body_timeseries_by_date_range.py b/tests/fitbit_client/resources/body_timeseries/test_get_body_timeseries_by_date_range.py
index 3fee224..35374cc 100644
--- a/tests/fitbit_client/resources/body_timeseries/test_get_body_timeseries_by_date_range.py
+++ b/tests/fitbit_client/resources/body_timeseries/test_get_body_timeseries_by_date_range.py
@@ -54,11 +54,13 @@ def test_get_body_timeseries_by_date_range_max_days(body_timeseries):
)
-def test_get_body_timeseries_by_date_range_makes_correct_request(body_timeseries, mock_response):
+def test_get_body_timeseries_by_date_range_makes_correct_request(
+ body_timeseries, mock_response_factory
+):
"""Test that the correct endpoint is called with proper parameters."""
# Set up the mock response
+ mock_response = mock_response_factory(200, {"expected": "response"})
body_timeseries.oauth.request.return_value = mock_response
- mock_response.json.return_value = {"expected": "response"}
# Call the method with valid parameters that don't exceed range limits
result = body_timeseries.get_body_timeseries_by_date_range(
diff --git a/tests/fitbit_client/resources/body_timeseries/test_get_bodyfat_timeseries_by_date.py b/tests/fitbit_client/resources/body_timeseries/test_get_bodyfat_timeseries_by_date.py
index e4dbe09..37b818e 100644
--- a/tests/fitbit_client/resources/body_timeseries/test_get_bodyfat_timeseries_by_date.py
+++ b/tests/fitbit_client/resources/body_timeseries/test_get_bodyfat_timeseries_by_date.py
@@ -36,11 +36,13 @@ def test_get_bodyfat_timeseries_by_date_period_validation(body_timeseries):
assert f"Period {period.value} not supported for body fat" in str(exc_info.value)
-def test_get_bodyfat_timeseries_by_date_makes_correct_request(body_timeseries, mock_response):
+def test_get_bodyfat_timeseries_by_date_makes_correct_request(
+ body_timeseries, mock_response_factory
+):
"""Test that the correct endpoint is called with proper parameters."""
# Set up the mock response
+ mock_response = mock_response_factory(200, {"expected": "response"})
body_timeseries.oauth.request.return_value = mock_response
- mock_response.json.return_value = {"expected": "response"}
# Call the method
result = body_timeseries.get_bodyfat_timeseries_by_date(
diff --git a/tests/fitbit_client/resources/body_timeseries/test_get_bodyfat_timeseries_by_date_range.py b/tests/fitbit_client/resources/body_timeseries/test_get_bodyfat_timeseries_by_date_range.py
index 2bb9945..48cb9e6 100644
--- a/tests/fitbit_client/resources/body_timeseries/test_get_bodyfat_timeseries_by_date_range.py
+++ b/tests/fitbit_client/resources/body_timeseries/test_get_bodyfat_timeseries_by_date_range.py
@@ -42,11 +42,13 @@ def test_get_bodyfat_timeseries_by_date_range_max_days(body_timeseries):
assert "body fat" in str(exc_info.value)
-def test_get_bodyfat_timeseries_by_date_range_makes_correct_request(body_timeseries, mock_response):
+def test_get_bodyfat_timeseries_by_date_range_makes_correct_request(
+ body_timeseries, mock_response_factory
+):
"""Test that the correct endpoint is called with proper parameters."""
# Set up the mock response
+ mock_response = mock_response_factory(200, {"expected": "response"})
body_timeseries.oauth.request.return_value = mock_response
- mock_response.json.return_value = {"expected": "response"}
# Call the method with a valid date range (under 30 days)
result = body_timeseries.get_bodyfat_timeseries_by_date_range(
diff --git a/tests/fitbit_client/resources/body_timeseries/test_get_weight_timeseries_by_date.py b/tests/fitbit_client/resources/body_timeseries/test_get_weight_timeseries_by_date.py
index eadf9c1..c96b441 100644
--- a/tests/fitbit_client/resources/body_timeseries/test_get_weight_timeseries_by_date.py
+++ b/tests/fitbit_client/resources/body_timeseries/test_get_weight_timeseries_by_date.py
@@ -36,11 +36,13 @@ def test_get_weight_timeseries_by_date_period_validation(body_timeseries):
assert f"Period {period.value} not supported for weight" in str(exc_info.value)
-def test_get_weight_timeseries_by_date_makes_correct_request(body_timeseries, mock_response):
+def test_get_weight_timeseries_by_date_makes_correct_request(
+ body_timeseries, mock_response_factory
+):
"""Test that the correct endpoint is called with proper parameters."""
# Set up the mock response
+ mock_response = mock_response_factory(200, {"expected": "response"})
body_timeseries.oauth.request.return_value = mock_response
- mock_response.json.return_value = {"expected": "response"}
# Call the method
result = body_timeseries.get_weight_timeseries_by_date(
diff --git a/tests/fitbit_client/resources/body_timeseries/test_get_weight_timeseries_by_date_range.py b/tests/fitbit_client/resources/body_timeseries/test_get_weight_timeseries_by_date_range.py
index 0833a11..aa18580 100644
--- a/tests/fitbit_client/resources/body_timeseries/test_get_weight_timeseries_by_date_range.py
+++ b/tests/fitbit_client/resources/body_timeseries/test_get_weight_timeseries_by_date_range.py
@@ -42,11 +42,13 @@ def test_get_weight_timeseries_by_date_range_max_days(body_timeseries):
assert "weight" in str(exc_info.value)
-def test_get_weight_timeseries_by_date_range_makes_correct_request(body_timeseries, mock_response):
+def test_get_weight_timeseries_by_date_range_makes_correct_request(
+ body_timeseries, mock_response_factory
+):
"""Test that the correct endpoint is called with proper parameters."""
# Set up the mock response
+ mock_response = mock_response_factory(200, {"expected": "response"})
body_timeseries.oauth.request.return_value = mock_response
- mock_response.json.return_value = {"expected": "response"}
# Call the method with a valid date range (under 31 days)
result = body_timeseries.get_weight_timeseries_by_date_range(
diff --git a/tests/fitbit_client/resources/friends/test_get_friends.py b/tests/fitbit_client/resources/friends/test_get_friends.py
index 8f9b079..7e716b0 100644
--- a/tests/fitbit_client/resources/friends/test_get_friends.py
+++ b/tests/fitbit_client/resources/friends/test_get_friends.py
@@ -3,23 +3,25 @@
"""Tests for the get_friends endpoint."""
-def test_get_friends(friends_resource, mock_oauth_session, mock_response):
+def test_get_friends(friends_resource, mock_oauth_session, mock_response_factory):
"""Test getting friends list"""
- mock_response.json.return_value = {
- "data": [
- {
- "type": "person",
- "id": "ABC123",
- "attributes": {
- "avatar": "http://example.com/avatar.jpg",
- "child": False,
- "friend": True,
- "name": "Test User",
- },
- }
- ]
- }
- mock_response.headers = {"content-type": "application/json"}
+ mock_response = mock_response_factory(
+ 200,
+ {
+ "data": [
+ {
+ "type": "person",
+ "id": "ABC123",
+ "attributes": {
+ "avatar": "http://example.com/avatar.jpg",
+ "child": False,
+ "friend": True,
+ "name": "Test User",
+ },
+ }
+ ]
+ },
+ )
mock_oauth_session.request.return_value = mock_response
result = friends_resource.get_friends()
assert len(result) == 1
diff --git a/tests/fitbit_client/resources/friends/test_get_friends_leaderboard.py b/tests/fitbit_client/resources/friends/test_get_friends_leaderboard.py
index bec034a..30c0cf1 100644
--- a/tests/fitbit_client/resources/friends/test_get_friends_leaderboard.py
+++ b/tests/fitbit_client/resources/friends/test_get_friends_leaderboard.py
@@ -3,26 +3,28 @@
"""Tests for the get_friends_leaderboard endpoint."""
-def test_get_friends_leaderboard(friends_resource, mock_oauth_session, mock_response):
+def test_get_friends_leaderboard(friends_resource, mock_oauth_session, mock_response_factory):
"""Test getting friends leaderboard"""
- mock_response.json.return_value = {
- "data": [
- {
- "type": "ranked-user",
- "id": "ABC123",
- "attributes": {"step-rank": 1, "step-summary": 50000},
- }
- ],
- "included": [
- {
- "avatar": "http://example.com/avatar.jpg",
- "child": False,
- "friend": True,
- "name": "Test User",
- }
- ],
- }
- mock_response.headers = {"content-type": "application/json"}
+ mock_response = mock_response_factory(
+ 200,
+ {
+ "data": [
+ {
+ "type": "ranked-user",
+ "id": "ABC123",
+ "attributes": {"step-rank": 1, "step-summary": 50000},
+ }
+ ],
+ "included": [
+ {
+ "avatar": "http://example.com/avatar.jpg",
+ "child": False,
+ "friend": True,
+ "name": "Test User",
+ }
+ ],
+ },
+ )
mock_oauth_session.request.return_value = mock_response
result = friends_resource.get_friends_leaderboard()
assert "data" in result
diff --git a/tests/fitbit_client/resources/heartrate_timeseries/test_get_heartrate_timeseries_by_date.py b/tests/fitbit_client/resources/heartrate_timeseries/test_get_heartrate_timeseries_by_date.py
index c600651..21f364d 100644
--- a/tests/fitbit_client/resources/heartrate_timeseries/test_get_heartrate_timeseries_by_date.py
+++ b/tests/fitbit_client/resources/heartrate_timeseries/test_get_heartrate_timeseries_by_date.py
@@ -15,7 +15,7 @@
def test_get_heartrate_timeseries_by_date_success(
- heartrate_resource, mock_oauth_session, mock_response
+ heartrate_resource, mock_oauth_session, mock_response_factory
):
"""Test successful retrieval of heart rate data by date and period"""
response_data = {
@@ -38,7 +38,7 @@ def test_get_heartrate_timeseries_by_date_success(
}
]
}
- mock_response.json.return_value = response_data
+ mock_response = mock_response_factory(200, response_data)
mock_oauth_session.request.return_value = mock_response
result = heartrate_resource.get_heartrate_timeseries_by_date(
date="2024-02-10", period=Period.ONE_DAY
@@ -54,9 +54,9 @@ def test_get_heartrate_timeseries_by_date_success(
)
-def test_get_heartrate_timeseries_by_date_today(heartrate_resource, mock_response):
+def test_get_heartrate_timeseries_by_date_today(heartrate_resource, mock_response_factory):
"""Test that 'today' is accepted as a valid date"""
- mock_response.json.return_value = {"activities-heart": []}
+ mock_response = mock_response_factory(200, {"activities-heart": []})
heartrate_resource.oauth.request.return_value = mock_response
result = heartrate_resource.get_heartrate_timeseries_by_date(
date="today", period=Period.ONE_DAY
diff --git a/tests/fitbit_client/resources/heartrate_timeseries/test_get_heartrate_timeseries_by_date_range.py b/tests/fitbit_client/resources/heartrate_timeseries/test_get_heartrate_timeseries_by_date_range.py
index 41faa7b..ee054be 100644
--- a/tests/fitbit_client/resources/heartrate_timeseries/test_get_heartrate_timeseries_by_date_range.py
+++ b/tests/fitbit_client/resources/heartrate_timeseries/test_get_heartrate_timeseries_by_date_range.py
@@ -13,7 +13,7 @@
from fitbit_client.exceptions import ParameterValidationException
-def test_get_heartrate_timeseries_by_date_range_success(heartrate_resource, mock_response):
+def test_get_heartrate_timeseries_by_date_range_success(heartrate_resource, mock_response_factory):
"""Test successful retrieval of heart rate data by date range"""
response_data = {
"activities-heart": [
@@ -21,7 +21,7 @@ def test_get_heartrate_timeseries_by_date_range_success(heartrate_resource, mock
{"dateTime": "2024-02-11", "value": {"restingHeartRate": 68, "heartRateZones": []}},
]
}
- mock_response.json.return_value = response_data
+ mock_response = mock_response_factory(200, response_data)
heartrate_resource.oauth.request.return_value = mock_response
result = heartrate_resource.get_heartrate_timeseries_by_date_range(
start_date="2024-02-10", end_date="2024-02-11"
@@ -37,9 +37,9 @@ def test_get_heartrate_timeseries_by_date_range_success(heartrate_resource, mock
)
-def test_get_heartrate_timeseries_by_date_range_today(heartrate_resource, mock_response):
+def test_get_heartrate_timeseries_by_date_range_today(heartrate_resource, mock_response_factory):
"""Test that 'today' is accepted in date range"""
- mock_response.json.return_value = {"activities-heart": []}
+ mock_response = mock_response_factory(200, {"activities-heart": []})
heartrate_resource.oauth.request.return_value = mock_response
result = heartrate_resource.get_heartrate_timeseries_by_date_range(
start_date="today", end_date="today"
diff --git a/tests/fitbit_client/resources/nutrition/test_add_favorite_foods.py b/tests/fitbit_client/resources/nutrition/test_add_favorite_foods.py
index c8952c0..2800c7c 100644
--- a/tests/fitbit_client/resources/nutrition/test_add_favorite_foods.py
+++ b/tests/fitbit_client/resources/nutrition/test_add_favorite_foods.py
@@ -3,10 +3,10 @@
"""Tests for the add_favorite_foods endpoint."""
-def test_add_favorite_foods_success(nutrition_resource, mock_response):
+def test_add_favorite_foods_success(nutrition_resource, mock_response_factory):
"""Test successful addition of a food to favorites"""
food_id = 12345
- mock_response.json.return_value = {"success": True}
+ mock_response = mock_response_factory(200, {"success": True})
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.add_favorite_foods(food_id=food_id)
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_create_food.py b/tests/fitbit_client/resources/nutrition/test_create_food.py
index 2fa5416..f542f8f 100644
--- a/tests/fitbit_client/resources/nutrition/test_create_food.py
+++ b/tests/fitbit_client/resources/nutrition/test_create_food.py
@@ -11,9 +11,11 @@
from fitbit_client.resources._constants import NutritionalValue
-def test_create_food_success(nutrition_resource, mock_response):
+def test_create_food_success(nutrition_resource, mock_response_factory):
"""Test successful creation of a new food"""
- mock_response.json.return_value = {"foodId": 12345, "name": "Test Food", "calories": 100}
+ mock_response = mock_response_factory(
+ 200, {"foodId": 12345, "name": "Test Food", "calories": 100}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_food(
name="Test Food",
@@ -47,9 +49,9 @@ def test_create_food_success(nutrition_resource, mock_response):
)
-def test_create_food_with_string_nutritional_values(nutrition_resource, mock_response):
+def test_create_food_with_string_nutritional_values(nutrition_resource, mock_response_factory):
"""Test creating food with string nutritional value keys"""
- mock_response.json.return_value = {"foodId": 12345, "name": "Test Food"}
+ mock_response = mock_response_factory(200, {"foodId": 12345, "name": "Test Food"})
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_food(
name="Test Food",
@@ -102,9 +104,11 @@ def test_create_food_calories_from_fat_must_be_integer(nutrition_resource):
assert "Calories from fat must be an integer" in str(exc_info.value)
-def test_create_food_with_calories_from_fat(nutrition_resource, mock_response):
+def test_create_food_with_calories_from_fat(nutrition_resource, mock_response_factory):
"""Test creating food with calories from fat as an integer"""
- mock_response.json.return_value = {"foodId": 12345, "name": "Test Food", "calories": 100}
+ mock_response = mock_response_factory(
+ 200, {"foodId": 12345, "name": "Test Food", "calories": 100}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_food(
diff --git a/tests/fitbit_client/resources/nutrition/test_create_food_goal.py b/tests/fitbit_client/resources/nutrition/test_create_food_goal.py
index 6eb01ad..e6a3a73 100644
--- a/tests/fitbit_client/resources/nutrition/test_create_food_goal.py
+++ b/tests/fitbit_client/resources/nutrition/test_create_food_goal.py
@@ -2,8 +2,6 @@
"""Tests for the create_food_goal endpoint."""
-# Third party imports
-
# Third party imports
from pytest import raises
@@ -12,9 +10,9 @@
from fitbit_client.resources._constants import FoodPlanIntensity
-def test_create_food_goal_with_calories_success(nutrition_resource, mock_response):
+def test_create_food_goal_with_calories_success(nutrition_resource, mock_response_factory):
"""Test successful creation of a food goal using calories"""
- mock_response.json.return_value = {"goals": {"calories": 2000}}
+ mock_response = mock_response_factory(200, {"goals": {"calories": 2000}})
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_food_goal(calories=2000)
assert result == mock_response.json.return_value
@@ -28,12 +26,11 @@ def test_create_food_goal_with_calories_success(nutrition_resource, mock_respons
)
-def test_create_food_goal_with_intensity_success(nutrition_resource, mock_response):
+def test_create_food_goal_with_intensity_success(nutrition_resource, mock_response_factory):
"""Test successful creation of a food goal using intensity"""
- mock_response.json.return_value = {
- "foodPlan": {"intensity": "EASIER"},
- "goals": {"calories": 2200},
- }
+ mock_response = mock_response_factory(
+ 200, {"foodPlan": {"intensity": "EASIER"}, "goals": {"calories": 2200}}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_food_goal(
intensity=FoodPlanIntensity.EASIER, personalized=True
diff --git a/tests/fitbit_client/resources/nutrition/test_create_food_goal_intensity.py b/tests/fitbit_client/resources/nutrition/test_create_food_goal_intensity.py
index 967b89e..b955416 100644
--- a/tests/fitbit_client/resources/nutrition/test_create_food_goal_intensity.py
+++ b/tests/fitbit_client/resources/nutrition/test_create_food_goal_intensity.py
@@ -2,15 +2,13 @@
"""Tests for the create_food_goal_intensity endpoint."""
-# Local imports
-
# Local imports
from fitbit_client.resources._constants import FoodPlanIntensity
-def test_create_food_goal_intensity_without_personalized(nutrition_resource, mock_response):
+def test_create_food_goal_intensity_without_personalized(nutrition_resource, mock_response_factory):
"""Test creating food goal with intensity but without personalized flag (lines 217-220)"""
- mock_response.json.return_value = {"foodPlan": {"intensity": "EASIER"}}
+ mock_response = mock_response_factory(200, {"foodPlan": {"intensity": "EASIER"}})
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_food_goal(intensity=FoodPlanIntensity.EASIER)
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_create_food_log.py b/tests/fitbit_client/resources/nutrition/test_create_food_log.py
index cdc1396..da0b24a 100644
--- a/tests/fitbit_client/resources/nutrition/test_create_food_log.py
+++ b/tests/fitbit_client/resources/nutrition/test_create_food_log.py
@@ -14,11 +14,11 @@
from fitbit_client.resources._constants import NutritionalValue
-def test_create_food_log_with_food_id_success(nutrition_resource, mock_response):
+def test_create_food_log_with_food_id_success(nutrition_resource, mock_response_factory):
"""Test successful creation of a food log entry using food ID"""
- mock_response.json.return_value = {
- "foodLog": {"logId": 12345, "loggedFood": {"foodId": 67890, "amount": 1.0}}
- }
+ mock_response = mock_response_factory(
+ 200, {"foodLog": {"logId": 12345, "loggedFood": {"foodId": 67890, "amount": 1.0}}}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_food_log(
date="2025-02-08",
@@ -46,11 +46,11 @@ def test_create_food_log_with_food_id_success(nutrition_resource, mock_response)
)
-def test_create_food_log_with_custom_food_success(nutrition_resource, mock_response):
+def test_create_food_log_with_custom_food_success(nutrition_resource, mock_response_factory):
"""Test successful creation of a food log entry using custom food details"""
- mock_response.json.return_value = {
- "foodLog": {"logId": 12345, "loggedFood": {"name": "Custom Food", "amount": 1.0}}
- }
+ mock_response = mock_response_factory(
+ 200, {"foodLog": {"logId": 12345, "loggedFood": {"name": "Custom Food", "amount": 1.0}}}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_food_log(
date="2025-02-08",
@@ -86,11 +86,11 @@ def test_create_food_log_with_custom_food_success(nutrition_resource, mock_respo
)
-def test_create_food_log_with_favorite_flag(nutrition_resource, mock_response):
+def test_create_food_log_with_favorite_flag(nutrition_resource, mock_response_factory):
"""Test that creating a food log with favorite=True sets the flag correctly"""
- mock_response.json.return_value = {
- "foodLog": {"logId": 12345, "loggedFood": {"foodId": 67890, "amount": 1.0}}
- }
+ mock_response = mock_response_factory(
+ 200, {"foodLog": {"logId": 12345, "loggedFood": {"foodId": 67890, "amount": 1.0}}}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_food_log(
date="2025-02-08",
@@ -142,9 +142,9 @@ def test_create_food_log_with_favorite_flag(nutrition_resource, mock_response):
)
-def test_create_food_log_with_brand_name_only(nutrition_resource, mock_response):
+def test_create_food_log_with_brand_name_only(nutrition_resource, mock_response_factory):
"""Test creating food log with only brand name (lines 172-174)"""
- mock_response.json.return_value = {"foodLog": {"logId": 12345}}
+ mock_response = mock_response_factory(200, {"foodLog": {"logId": 12345}})
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_food_log(
date="2025-02-08",
@@ -174,9 +174,9 @@ def test_create_food_log_with_brand_name_only(nutrition_resource, mock_response)
)
-def test_create_food_log_none_handling(nutrition_resource, mock_response):
+def test_create_food_log_none_handling(nutrition_resource, mock_response_factory):
"""Test handling of None values for food_name and calories"""
- mock_response.json.return_value = {"foodLog": {"logId": 12345}}
+ mock_response = mock_response_factory(200, {"foodLog": {"logId": 12345}})
nutrition_resource.oauth.request.return_value = mock_response
# Save original method
@@ -202,7 +202,7 @@ def test_method(date, meal_type_id, unit_id, amount, **kwargs):
if calories is not None:
params["calories"] = calories
- return mock_response.json.return_value
+ return mock_response.json()
try:
# Replace with our test method
@@ -260,10 +260,9 @@ def test_create_food_log_invalid_date(nutrition_resource):
)
-def test_create_food_log_allows_today(nutrition_resource, mock_response):
+def test_create_food_log_allows_today(nutrition_resource, mock_response_factory):
"""Test that 'today' is accepted as a valid date"""
- mock_response.json.return_value = {"foodLog": {"logId": 12345}}
- mock_response.headers = {"content-type": "application/json"}
+ mock_response = mock_response_factory(200, {"foodLog": {"logId": 12345}})
nutrition_resource.oauth.request.return_value = mock_response
nutrition_resource.create_food_log(
date="today", meal_type_id=MealType.BREAKFAST, unit_id=147, amount=100.0, food_id=67890
diff --git a/tests/fitbit_client/resources/nutrition/test_create_food_log_custom_minimal.py b/tests/fitbit_client/resources/nutrition/test_create_food_log_custom_minimal.py
index 814902d..193de9a 100644
--- a/tests/fitbit_client/resources/nutrition/test_create_food_log_custom_minimal.py
+++ b/tests/fitbit_client/resources/nutrition/test_create_food_log_custom_minimal.py
@@ -2,15 +2,13 @@
"""Tests for the create_food_log_custom_minimal endpoint."""
-# Local imports
-
# Local imports
from fitbit_client.resources._constants import MealType
-def test_create_food_log_custom_minimal(nutrition_resource, mock_response):
+def test_create_food_log_custom_minimal(nutrition_resource, mock_response_factory):
"""Test creating custom food log with minimal parameters (no brand or nutritional values)"""
- mock_response.json.return_value = {"foodLog": {"logId": 12345}}
+ mock_response = mock_response_factory(200, {"foodLog": {"logId": 12345}})
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_food_log(
date="2025-02-08",
diff --git a/tests/fitbit_client/resources/nutrition/test_create_meal.py b/tests/fitbit_client/resources/nutrition/test_create_meal.py
index 4b1fe03..cd49866 100644
--- a/tests/fitbit_client/resources/nutrition/test_create_meal.py
+++ b/tests/fitbit_client/resources/nutrition/test_create_meal.py
@@ -3,16 +3,19 @@
"""Tests for the create_meal endpoint."""
-def test_create_meal_success(nutrition_resource, mock_response):
+def test_create_meal_success(nutrition_resource, mock_response_factory):
"""Test successful creation of a meal"""
- mock_response.json.return_value = {
- "meal": {
- "id": 12345,
- "name": "Test Meal",
- "description": "Test meal description",
- "mealFoods": [{"foodId": 67890, "amount": 100.0, "unitId": 147}],
- }
- }
+ mock_response = mock_response_factory(
+ 200,
+ {
+ "meal": {
+ "id": 12345,
+ "name": "Test Meal",
+ "description": "Test meal description",
+ "mealFoods": [{"foodId": 67890, "amount": 100.0, "unitId": 147}],
+ }
+ },
+ )
nutrition_resource.oauth.request.return_value = mock_response
foods = [{"food_id": 67890, "amount": 100.0, "unit_id": 147}]
result = nutrition_resource.create_meal(
diff --git a/tests/fitbit_client/resources/nutrition/test_create_water_goal.py b/tests/fitbit_client/resources/nutrition/test_create_water_goal.py
index b04f9d7..149005f 100644
--- a/tests/fitbit_client/resources/nutrition/test_create_water_goal.py
+++ b/tests/fitbit_client/resources/nutrition/test_create_water_goal.py
@@ -3,9 +3,11 @@
"""Tests for the create_water_goal endpoint."""
-def test_create_water_goal_success(nutrition_resource, mock_response):
+def test_create_water_goal_success(nutrition_resource, mock_response_factory):
"""Test successful creation of a water goal"""
- mock_response.json.return_value = {"goal": {"goal": 2000.0, "startDate": "2025-02-08"}}
+ mock_response = mock_response_factory(
+ 200, {"goal": {"goal": 2000.0, "startDate": "2025-02-08"}}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_water_goal(target=2000.0)
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_create_water_log.py b/tests/fitbit_client/resources/nutrition/test_create_water_log.py
index 5f589aa..c96e4cc 100644
--- a/tests/fitbit_client/resources/nutrition/test_create_water_log.py
+++ b/tests/fitbit_client/resources/nutrition/test_create_water_log.py
@@ -2,8 +2,6 @@
"""Tests for the create_water_log endpoint."""
-# Third party imports
-
# Third party imports
from pytest import raises
@@ -12,9 +10,9 @@
from fitbit_client.resources._constants import WaterUnit
-def test_create_water_log_success(nutrition_resource, mock_response):
+def test_create_water_log_success(nutrition_resource, mock_response_factory):
"""Test successful creation of a water log entry"""
- mock_response.json.return_value = {"waterLog": {"logId": 12345, "amount": 500.0}}
+ mock_response = mock_response_factory(200, {"waterLog": {"logId": 12345, "amount": 500.0}})
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.create_water_log(
amount=500.0, date="2025-02-08", unit=WaterUnit.MILLILITERS
@@ -36,8 +34,9 @@ def test_create_water_log_invalid_date(nutrition_resource):
nutrition_resource.create_water_log(amount=500.0, date="invalid-date")
-def test_create_water_log_allows_today(nutrition_resource, mock_response):
+def test_create_water_log_allows_today(nutrition_resource, mock_response_factory):
"""Test that 'today' is accepted as a valid date"""
+ mock_response = mock_response_factory(200)
mock_response.json.return_value = {"waterLog": {"logId": 12345}}
mock_response.headers = {"content-type": "application/json"}
nutrition_resource.oauth.request.return_value = mock_response
diff --git a/tests/fitbit_client/resources/nutrition/test_custom_user_id.py b/tests/fitbit_client/resources/nutrition/test_custom_user_id.py
index fb40804..e1615ef 100644
--- a/tests/fitbit_client/resources/nutrition/test_custom_user_id.py
+++ b/tests/fitbit_client/resources/nutrition/test_custom_user_id.py
@@ -8,7 +8,7 @@
from fitbit_client.resources._constants import MealType
-def test_custom_user_id(nutrition_resource, mock_response):
+def test_custom_user_id(nutrition_resource, mock_response_factory):
"""Test that endpoints correctly handle custom user IDs"""
custom_user_id = "123ABC"
test_cases = [
@@ -35,7 +35,7 @@ def test_custom_user_id(nutrition_resource, mock_response):
f"https://api.fitbit.com/1/user/{custom_user_id}/foods/log/water/date/2025-02-08.json",
),
]
- mock_response.json.return_value = {"success": True}
+ mock_response = mock_response_factory(200, {"success": True})
nutrition_resource.oauth.request.return_value = mock_response
for method, params, expected_url in test_cases:
result = method(**params)
diff --git a/tests/fitbit_client/resources/nutrition/test_delete_custom_food.py b/tests/fitbit_client/resources/nutrition/test_delete_custom_food.py
index 002d5aa..e3ee88d 100644
--- a/tests/fitbit_client/resources/nutrition/test_delete_custom_food.py
+++ b/tests/fitbit_client/resources/nutrition/test_delete_custom_food.py
@@ -3,9 +3,9 @@
"""Tests for the delete_custom_food endpoint."""
-def test_delete_custom_food_success(nutrition_resource, mock_response):
+def test_delete_custom_food_success(nutrition_resource, mock_response_factory):
"""Test successful deletion of a custom food"""
- mock_response.status_code = 204
+ mock_response = mock_response_factory(204)
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.delete_custom_food(food_id=12345)
assert result is None
diff --git a/tests/fitbit_client/resources/nutrition/test_delete_favorite_foods.py b/tests/fitbit_client/resources/nutrition/test_delete_favorite_foods.py
index ca75a83..1dbaaad 100644
--- a/tests/fitbit_client/resources/nutrition/test_delete_favorite_foods.py
+++ b/tests/fitbit_client/resources/nutrition/test_delete_favorite_foods.py
@@ -3,9 +3,9 @@
"""Tests for the delete_favorite_foods endpoint."""
-def test_delete_favorite_food_success(nutrition_resource, mock_response):
+def test_delete_favorite_food_success(nutrition_resource, mock_response_factory):
"""Test successful deletion of a favorite food"""
- mock_response.status_code = 204
+ mock_response = mock_response_factory(204)
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.delete_favorite_food(food_id=12345)
assert result is None
diff --git a/tests/fitbit_client/resources/nutrition/test_delete_food_log.py b/tests/fitbit_client/resources/nutrition/test_delete_food_log.py
index a7cd018..bd0a88b 100644
--- a/tests/fitbit_client/resources/nutrition/test_delete_food_log.py
+++ b/tests/fitbit_client/resources/nutrition/test_delete_food_log.py
@@ -3,9 +3,9 @@
"""Tests for the delete_food_log endpoint."""
-def test_delete_food_log_success(nutrition_resource, mock_response):
+def test_delete_food_log_success(nutrition_resource, mock_response_factory):
"""Test successful deletion of a food log entry"""
- mock_response.status_code = 204
+ mock_response = mock_response_factory(204)
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.delete_food_log(food_log_id=12345)
assert result is None
diff --git a/tests/fitbit_client/resources/nutrition/test_delete_meal.py b/tests/fitbit_client/resources/nutrition/test_delete_meal.py
index 8f5ddee..e859fb5 100644
--- a/tests/fitbit_client/resources/nutrition/test_delete_meal.py
+++ b/tests/fitbit_client/resources/nutrition/test_delete_meal.py
@@ -3,9 +3,9 @@
"""Tests for the delete_meal endpoint."""
-def test_delete_meal_success(nutrition_resource, mock_response):
+def test_delete_meal_success(nutrition_resource, mock_response_factory):
"""Test successful deletion of a meal"""
- mock_response.status_code = 204
+ mock_response = mock_response_factory(204)
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.delete_meal(meal_id=12345)
assert result is None
diff --git a/tests/fitbit_client/resources/nutrition/test_delete_water_log.py b/tests/fitbit_client/resources/nutrition/test_delete_water_log.py
index 7434b57..180652f 100644
--- a/tests/fitbit_client/resources/nutrition/test_delete_water_log.py
+++ b/tests/fitbit_client/resources/nutrition/test_delete_water_log.py
@@ -3,9 +3,9 @@
"""Tests for the delete_water_log endpoint."""
-def test_delete_water_log_success(nutrition_resource, mock_response):
+def test_delete_water_log_success(nutrition_resource, mock_response_factory):
"""Test successful deletion of a water log entry"""
- mock_response.status_code = 204
+ mock_response = mock_response_factory(204)
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.delete_water_log(water_log_id=12345)
assert result is None
diff --git a/tests/fitbit_client/resources/nutrition/test_get_favorite_foods.py b/tests/fitbit_client/resources/nutrition/test_get_favorite_foods.py
index e5920ab..93ccc71 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_favorite_foods.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_favorite_foods.py
@@ -3,11 +3,11 @@
"""Tests for the get_favorite_foods endpoint."""
-def test_get_favorite_foods_success(nutrition_resource, mock_response):
+def test_get_favorite_foods_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of favorite foods"""
- mock_response.json.return_value = [
- {"foodId": 12345, "name": "Test Food", "defaultServingSize": 100.0, "calories": 100}
- ]
+ mock_response = mock_response_factory(
+ 200, [{"foodId": 12345, "name": "Test Food", "defaultServingSize": 100.0, "calories": 100}]
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_favorite_foods()
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_get_food.py b/tests/fitbit_client/resources/nutrition/test_get_food.py
index f096cfd..3475cb3 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_food.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_food.py
@@ -3,11 +3,19 @@
"""Tests for the get_food endpoint."""
-def test_get_food_success(nutrition_resource, mock_response):
+def test_get_food_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of food details"""
- mock_response.json.return_value = {
- "food": {"foodId": 12345, "name": "Test Food", "calories": 100, "defaultServingSize": 100.0}
- }
+ mock_response = mock_response_factory(
+ 200,
+ {
+ "food": {
+ "foodId": 12345,
+ "name": "Test Food",
+ "calories": 100,
+ "defaultServingSize": 100.0,
+ }
+ },
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_food(food_id=12345)
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_get_food_goals.py b/tests/fitbit_client/resources/nutrition/test_get_food_goals.py
index f67f17e..cf90fc6 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_food_goals.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_food_goals.py
@@ -3,12 +3,11 @@
"""Tests for the get_food_goals endpoint."""
-def test_get_food_goals_success(nutrition_resource, mock_response):
+def test_get_food_goals_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of food goals"""
- mock_response.json.return_value = {
- "goals": {"calories": 2000},
- "foodPlan": {"intensity": "MAINTENANCE"},
- }
+ mock_response = mock_response_factory(
+ 200, {"goals": {"calories": 2000}, "foodPlan": {"intensity": "MAINTENANCE"}}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_food_goals()
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_get_food_locales.py b/tests/fitbit_client/resources/nutrition/test_get_food_locales.py
index ddee935..54d0d7b 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_food_locales.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_food_locales.py
@@ -3,12 +3,15 @@
"""Tests for the get_food_locales endpoint."""
-def test_get_food_locales_success(nutrition_resource, mock_response):
+def test_get_food_locales_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of food locales"""
- mock_response.json.return_value = [
- {"value": "en_US", "label": "United States"},
- {"value": "en_GB", "label": "United Kingdom"},
- ]
+ mock_response = mock_response_factory(
+ 200,
+ [
+ {"value": "en_US", "label": "United States"},
+ {"value": "en_GB", "label": "United Kingdom"},
+ ],
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_food_locales()
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_get_food_log.py b/tests/fitbit_client/resources/nutrition/test_get_food_log.py
index bbee982..82514a3 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_food_log.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_food_log.py
@@ -11,12 +11,15 @@
from fitbit_client.exceptions import InvalidDateException
-def test_get_food_log_success(nutrition_resource, mock_response):
+def test_get_food_log_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of food log entries"""
- mock_response.json.return_value = {
- "foods": [{"logId": 12345, "loggedFood": {"foodId": 67890, "amount": 100.0}}],
- "summary": {"calories": 500},
- }
+ mock_response = mock_response_factory(
+ 200,
+ {
+ "foods": [{"logId": 12345, "loggedFood": {"foodId": 67890, "amount": 100.0}}],
+ "summary": {"calories": 500},
+ },
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_food_log(date="2025-02-08")
assert result == mock_response.json.return_value
@@ -36,9 +39,8 @@ def test_get_food_log_invalid_date(nutrition_resource):
nutrition_resource.get_food_log("invalid-date")
-def test_get_food_log_allows_today(nutrition_resource, mock_response):
+def test_get_food_log_allows_today(nutrition_resource, mock_response_factory):
"""Test that 'today' is accepted as a valid date"""
- mock_response.json.return_value = {"foods": []}
- mock_response.headers = {"content-type": "application/json"}
+ mock_response = mock_response_factory(200, {"foods": []})
nutrition_resource.oauth.request.return_value = mock_response
nutrition_resource.get_food_log("today")
diff --git a/tests/fitbit_client/resources/nutrition/test_get_food_units.py b/tests/fitbit_client/resources/nutrition/test_get_food_units.py
index d083384..9249bb4 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_food_units.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_food_units.py
@@ -3,12 +3,15 @@
"""Tests for the get_food_units endpoint."""
-def test_get_food_units_success(nutrition_resource, mock_response):
+def test_get_food_units_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of food units"""
- mock_response.json.return_value = [
- {"id": 147, "name": "gram", "plural": "grams"},
- {"id": 204, "name": "medium", "plural": "mediums"},
- ]
+ mock_response = mock_response_factory(
+ 200,
+ [
+ {"id": 147, "name": "gram", "plural": "grams"},
+ {"id": 204, "name": "medium", "plural": "mediums"},
+ ],
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_food_units()
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_get_frequent_foods.py b/tests/fitbit_client/resources/nutrition/test_get_frequent_foods.py
index 2a5ba86..8f4baf5 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_frequent_foods.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_frequent_foods.py
@@ -3,11 +3,11 @@
"""Tests for the get_frequent_foods endpoint."""
-def test_get_frequent_foods_success(nutrition_resource, mock_response):
+def test_get_frequent_foods_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of frequent foods"""
- mock_response.json.return_value = [
- {"foodId": 12345, "name": "Test Food", "amount": 100.0, "mealTypeId": 1}
- ]
+ mock_response = mock_response_factory(
+ 200, [{"foodId": 12345, "name": "Test Food", "amount": 100.0, "mealTypeId": 1}]
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_frequent_foods()
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_get_meal.py b/tests/fitbit_client/resources/nutrition/test_get_meal.py
index 08be1fe..ace034e 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_meal.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_meal.py
@@ -3,16 +3,19 @@
"""Tests for the get_meal endpoint."""
-def test_get_meal_success(nutrition_resource, mock_response):
+def test_get_meal_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of a meal"""
- mock_response.json.return_value = {
- "meal": {
- "id": 12345,
- "name": "Test Meal",
- "description": "Test meal description",
- "mealFoods": [{"foodId": 67890, "amount": 100.0, "unitId": 147}],
- }
- }
+ mock_response = mock_response_factory(
+ 200,
+ {
+ "meal": {
+ "id": 12345,
+ "name": "Test Meal",
+ "description": "Test meal description",
+ "mealFoods": [{"foodId": 67890, "amount": 100.0, "unitId": 147}],
+ }
+ },
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_meal(meal_id=12345)
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_get_meals.py b/tests/fitbit_client/resources/nutrition/test_get_meals.py
index 9c95a77..8adc6d0 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_meals.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_meals.py
@@ -3,18 +3,21 @@
"""Tests for the get_meals endpoint."""
-def test_get_meals_success(nutrition_resource, mock_response):
+def test_get_meals_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of all meals"""
- mock_response.json.return_value = {
- "meals": [
- {
- "id": 12345,
- "name": "Test Meal",
- "description": "Test meal description",
- "mealFoods": [{"foodId": 67890, "amount": 100.0, "unitId": 147}],
- }
- ]
- }
+ mock_response = mock_response_factory(
+ 200,
+ {
+ "meals": [
+ {
+ "id": 12345,
+ "name": "Test Meal",
+ "description": "Test meal description",
+ "mealFoods": [{"foodId": 67890, "amount": 100.0, "unitId": 147}],
+ }
+ ]
+ },
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_meals()
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_get_recent_foods.py b/tests/fitbit_client/resources/nutrition/test_get_recent_foods.py
index d48168f..e72f676 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_recent_foods.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_recent_foods.py
@@ -3,11 +3,12 @@
"""Tests for the get_recent_foods endpoint."""
-def test_get_recent_foods_success(nutrition_resource, mock_response):
+def test_get_recent_foods_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of recent foods"""
- mock_response.json.return_value = [
- {"foodId": 12345, "name": "Test Food", "amount": 100.0, "dateLastEaten": "2025-02-08"}
- ]
+ mock_response = mock_response_factory(
+ 200,
+ [{"foodId": 12345, "name": "Test Food", "amount": 100.0, "dateLastEaten": "2025-02-08"}],
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_recent_foods()
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_get_water_goal.py b/tests/fitbit_client/resources/nutrition/test_get_water_goal.py
index 284633d..ba0be99 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_water_goal.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_water_goal.py
@@ -3,9 +3,11 @@
"""Tests for the get_water_goal endpoint."""
-def test_get_water_goal_success(nutrition_resource, mock_response):
+def test_get_water_goal_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of water goal"""
- mock_response.json.return_value = {"goal": {"goal": 2000.0, "startDate": "2025-02-08"}}
+ mock_response = mock_response_factory(
+ 200, {"goal": {"goal": 2000.0, "startDate": "2025-02-08"}}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_water_goal()
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_get_water_log.py b/tests/fitbit_client/resources/nutrition/test_get_water_log.py
index 65dd8d2..4cd4fc5 100644
--- a/tests/fitbit_client/resources/nutrition/test_get_water_log.py
+++ b/tests/fitbit_client/resources/nutrition/test_get_water_log.py
@@ -11,12 +11,11 @@
from fitbit_client.exceptions import InvalidDateException
-def test_get_water_log_success(nutrition_resource, mock_response):
+def test_get_water_log_success(nutrition_resource, mock_response_factory):
"""Test successful retrieval of water log entries"""
- mock_response.json.return_value = {
- "water": [{"logId": 12345, "amount": 500.0}],
- "summary": {"water": 500.0},
- }
+ mock_response = mock_response_factory(
+ 200, {"water": [{"logId": 12345, "amount": 500.0}], "summary": {"water": 500.0}}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.get_water_log(date="2025-02-08")
assert result == mock_response.json.return_value
@@ -36,9 +35,8 @@ def test_get_water_log_invalid_date(nutrition_resource):
nutrition_resource.get_water_log("invalid-date")
-def test_get_water_log_allows_today(nutrition_resource, mock_response):
+def test_get_water_log_allows_today(nutrition_resource, mock_response_factory):
"""Test that 'today' is accepted as a valid date"""
- mock_response.json.return_value = {"water": []}
- mock_response.headers = {"content-type": "application/json"}
+ mock_response = mock_response_factory(200, {"water": []})
nutrition_resource.oauth.request.return_value = mock_response
nutrition_resource.get_water_log("today")
diff --git a/tests/fitbit_client/resources/nutrition/test_search_foods.py b/tests/fitbit_client/resources/nutrition/test_search_foods.py
index d1494bc..e0deea2 100644
--- a/tests/fitbit_client/resources/nutrition/test_search_foods.py
+++ b/tests/fitbit_client/resources/nutrition/test_search_foods.py
@@ -3,11 +3,12 @@
"""Tests for the search_foods endpoint."""
-def test_search_foods_success(nutrition_resource, mock_response):
+def test_search_foods_success(nutrition_resource, mock_response_factory):
"""Test successful food search"""
- mock_response.json.return_value = {
- "foods": [{"foodId": 12345, "name": "Test Food", "brand": "Test Brand", "calories": 100}]
- }
+ mock_response = mock_response_factory(
+ 200,
+ {"foods": [{"foodId": 12345, "name": "Test Food", "brand": "Test Brand", "calories": 100}]},
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.search_foods(query="test food")
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/nutrition/test_update_food_log.py b/tests/fitbit_client/resources/nutrition/test_update_food_log.py
index 7c17b8d..c7cdb65 100644
--- a/tests/fitbit_client/resources/nutrition/test_update_food_log.py
+++ b/tests/fitbit_client/resources/nutrition/test_update_food_log.py
@@ -12,11 +12,11 @@
from fitbit_client.resources._constants import MealType
-def test_update_food_log_with_unit_amount_success(nutrition_resource, mock_response):
+def test_update_food_log_with_unit_amount_success(nutrition_resource, mock_response_factory):
"""Test successful update of a food log entry with unit and amount"""
- mock_response.json.return_value = {
- "foodLog": {"logId": 12345, "loggedFood": {"foodId": 67890, "amount": 200.0}}
- }
+ mock_response = mock_response_factory(
+ 200, {"foodLog": {"logId": 12345, "loggedFood": {"foodId": 67890, "amount": 200.0}}}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.update_food_log(
food_log_id=12345, meal_type_id=MealType.LUNCH, unit_id=147, amount=200.0
@@ -32,9 +32,11 @@ def test_update_food_log_with_unit_amount_success(nutrition_resource, mock_respo
)
-def test_update_food_log_with_calories_success(nutrition_resource, mock_response):
+def test_update_food_log_with_calories_success(nutrition_resource, mock_response_factory):
"""Test successful update of a food log entry with calories"""
- mock_response.json.return_value = {"foodLog": {"logId": 12345, "loggedFood": {"calories": 300}}}
+ mock_response = mock_response_factory(
+ 200, {"foodLog": {"logId": 12345, "loggedFood": {"calories": 300}}}
+ )
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.update_food_log(
food_log_id=12345, meal_type_id=MealType.LUNCH, calories=300
diff --git a/tests/fitbit_client/resources/nutrition/test_update_meal.py b/tests/fitbit_client/resources/nutrition/test_update_meal.py
index 36ae33d..7450746 100644
--- a/tests/fitbit_client/resources/nutrition/test_update_meal.py
+++ b/tests/fitbit_client/resources/nutrition/test_update_meal.py
@@ -3,16 +3,19 @@
"""Tests for the update_meal endpoint."""
-def test_update_meal_success(nutrition_resource, mock_response):
+def test_update_meal_success(nutrition_resource, mock_response_factory):
"""Test successful update of a meal"""
- mock_response.json.return_value = {
- "meal": {
- "id": 12345,
- "name": "Updated Meal",
- "description": "Updated description",
- "mealFoods": [{"foodId": 67890, "amount": 200.0, "unitId": 147}],
- }
- }
+ mock_response = mock_response_factory(
+ 200,
+ {
+ "meal": {
+ "id": 12345,
+ "name": "Updated Meal",
+ "description": "Updated description",
+ "mealFoods": [{"foodId": 67890, "amount": 200.0, "unitId": 147}],
+ }
+ },
+ )
nutrition_resource.oauth.request.return_value = mock_response
foods = [{"food_id": 67890, "amount": 200.0, "unit_id": 147}]
result = nutrition_resource.update_meal(
diff --git a/tests/fitbit_client/resources/nutrition/test_update_water_log.py b/tests/fitbit_client/resources/nutrition/test_update_water_log.py
index e472197..8eda88a 100644
--- a/tests/fitbit_client/resources/nutrition/test_update_water_log.py
+++ b/tests/fitbit_client/resources/nutrition/test_update_water_log.py
@@ -8,9 +8,9 @@
from fitbit_client.resources._constants import WaterUnit
-def test_update_water_log_success(nutrition_resource, mock_response):
+def test_update_water_log_success(nutrition_resource, mock_response_factory):
"""Test successful update of a water log entry"""
- mock_response.json.return_value = {"waterLog": {"logId": 12345, "amount": 1000.0}}
+ mock_response = mock_response_factory(200, {"waterLog": {"logId": 12345, "amount": 1000.0}})
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.update_water_log(
water_log_id=12345, amount=1000.0, unit=WaterUnit.MILLILITERS
@@ -26,9 +26,9 @@ def test_update_water_log_success(nutrition_resource, mock_response):
)
-def test_update_water_log_without_unit(nutrition_resource, mock_response):
+def test_update_water_log_without_unit(nutrition_resource, mock_response_factory):
"""Test updating water log without specifying unit (lines 733-735)"""
- mock_response.json.return_value = {"waterLog": {"logId": 12345, "amount": 1000.0}}
+ mock_response = mock_response_factory(200, {"waterLog": {"logId": 12345, "amount": 1000.0}})
nutrition_resource.oauth.request.return_value = mock_response
result = nutrition_resource.update_water_log(water_log_id=12345, amount=1000.0)
assert result == mock_response.json.return_value
diff --git a/tests/fitbit_client/resources/test_base.py b/tests/fitbit_client/resources/test_base.py
index aee1cd0..184ff1c 100644
--- a/tests/fitbit_client/resources/test_base.py
+++ b/tests/fitbit_client/resources/test_base.py
@@ -258,17 +258,18 @@ def test_log_response_for_error_without_content(base_resource, mock_logger):
# -----------------------------------------------------------------------------
-def test_handle_json_response(base_resource, mock_response):
+def test_handle_json_response(base_resource, mock_response_factory):
"""Test JSON response handling"""
- mock_response.json.return_value = {"data": "test"}
- mock_response.status_code = 200
+ expected_data = {"data": "test"}
+ mock_response = mock_response_factory(200, expected_data)
result = base_resource._handle_json_response("test_method", "test/endpoint", mock_response)
- assert result == {"data": "test"}
+ assert result == expected_data
-def test_handle_json_response_invalid(base_resource, mock_response):
+def test_handle_json_response_invalid(base_resource, mock_response_factory):
"""Test invalid JSON handling"""
+ mock_response = mock_response_factory(200)
mock_response.json.side_effect = JSONDecodeError("Invalid JSON", "doc", 0)
mock_response.text = "Invalid {json"
@@ -295,44 +296,49 @@ def test_handle_json_response_with_invalid_json(base_resource, mock_logger):
# -----------------------------------------------------------------------------
-def test_make_request_json_success(base_resource, mock_oauth_session, mock_response):
+def test_make_request_json_success(base_resource, mock_oauth_session, mock_response_factory):
"""Test successful JSON request"""
- mock_response.json.return_value = {"success": True}
- mock_response.headers = {"content-type": "application/json"}
- mock_response.status_code = 200
+ expected_data = {"success": True}
+ mock_response = mock_response_factory(
+ 200, expected_data, headers={"content-type": "application/json"}
+ )
mock_oauth_session.request.return_value = mock_response
result = base_resource._make_request("test/endpoint")
- assert result == {"success": True}
+ assert result == expected_data
-def test_make_request_no_content(base_resource, mock_oauth_session, mock_response):
+def test_make_request_no_content(base_resource, mock_oauth_session, mock_response_factory):
"""Test request with no content"""
- mock_response.status_code = 204
- mock_response.headers = {}
- mock_response.json.return_value = {"success": True}
+ mock_response = mock_response_factory(204, headers={})
mock_oauth_session.request.return_value = mock_response
result = base_resource._make_request("test/endpoint")
assert result is None
-def test_make_request_xml_response(base_resource, mock_oauth_session, mock_response):
+def test_make_request_xml_response(base_resource, mock_oauth_session, mock_response_factory):
"""Test XML response handling"""
+ mock_response = mock_response_factory(
+ 200,
+ headers={"content-type": "application/vnd.garmin.tcx+xml"},
+ content_type="application/vnd.garmin.tcx+xml",
+ )
mock_response.text = "data"
- mock_response.headers = {"content-type": "application/vnd.garmin.tcx+xml"}
- mock_response.status_code = 200
mock_oauth_session.request.return_value = mock_response
result = base_resource._make_request("test/endpoint")
assert result == "data"
-def test_make_request_unexpected_content_type(base_resource, mock_oauth_session, mock_response):
+def test_make_request_unexpected_content_type(
+ base_resource, mock_oauth_session, mock_response_factory
+):
"""Test handling of unexpected content type"""
+ mock_response = mock_response_factory(
+ 200, headers={"content-type": "text/plain"}, content_type="text/plain"
+ )
mock_response.text = "some data"
- mock_response.headers = {"content-type": "text/plain"}
- mock_response.status_code = 200
mock_oauth_session.request.return_value = mock_response
result = base_resource._make_request("test/endpoint")