|
1 | 1 | """Test cases for extractor module.""" |
2 | 2 |
|
| 3 | +import json |
3 | 4 | import pytest |
4 | 5 | from unittest.mock import Mock, patch, MagicMock |
5 | 6 | from openai import RateLimitError, APITimeoutError, APIError |
@@ -76,10 +77,28 @@ def test_validate_input_valid(self, extractor): |
76 | 77 | @patch('structured_output_cookbook.extractor.time.sleep') |
77 | 78 | def test_extract_with_retry_on_rate_limit(self, mock_sleep, extractor): |
78 | 79 | """Test extraction with retry on rate limit error.""" |
| 80 | + # Complete mock response with all required fields |
| 81 | + complete_recipe = { |
| 82 | + "name": "Test Recipe", |
| 83 | + "description": "A delicious test recipe", |
| 84 | + "cuisine": "Italian", |
| 85 | + "difficulty": "easy", |
| 86 | + "prep_time": "15 minutes", |
| 87 | + "cook_time": "30 minutes", |
| 88 | + "total_time": "45 minutes", |
| 89 | + "servings": 4, |
| 90 | + "ingredients": [ |
| 91 | + {"name": "flour", "quantity": "2", "unit": "cups", "notes": None} |
| 92 | + ], |
| 93 | + "instructions": ["Mix ingredients", "Cook until done"], |
| 94 | + "tags": ["vegetarian", "easy"], |
| 95 | + "nutrition": {"calories": 200} |
| 96 | + } |
| 97 | + |
79 | 98 | # Mock the OpenAI response |
80 | 99 | mock_response = Mock() |
81 | 100 | mock_response.choices = [Mock()] |
82 | | - mock_response.choices[0].message.content = '{"name": "Test Recipe"}' |
| 101 | + mock_response.choices[0].message.content = json.dumps(complete_recipe) |
83 | 102 | mock_response.model = "gpt-4o-mini" |
84 | 103 | mock_response.usage = Mock() |
85 | 104 | mock_response.usage.total_tokens = 100 |
@@ -110,10 +129,28 @@ def test_extract_with_retry_on_rate_limit(self, mock_sleep, extractor): |
110 | 129 |
|
111 | 130 | def test_extract_success(self, extractor): |
112 | 131 | """Test successful extraction.""" |
| 132 | + # Complete mock response with all required fields |
| 133 | + complete_recipe = { |
| 134 | + "name": "Test Recipe", |
| 135 | + "description": "A delicious test recipe", |
| 136 | + "cuisine": "Italian", |
| 137 | + "difficulty": "easy", |
| 138 | + "prep_time": "15 minutes", |
| 139 | + "cook_time": "30 minutes", |
| 140 | + "total_time": "45 minutes", |
| 141 | + "servings": 4, |
| 142 | + "ingredients": [ |
| 143 | + {"name": "flour", "quantity": "2", "unit": "cups", "notes": None} |
| 144 | + ], |
| 145 | + "instructions": ["Mix ingredients", "Cook until done"], |
| 146 | + "tags": ["vegetarian", "easy"], |
| 147 | + "nutrition": {"calories": 200} |
| 148 | + } |
| 149 | + |
113 | 150 | # Mock the OpenAI response |
114 | 151 | mock_response = Mock() |
115 | 152 | mock_response.choices = [Mock()] |
116 | | - mock_response.choices[0].message.content = '{"name": "Test Recipe", "ingredients": [], "instructions": []}' |
| 153 | + mock_response.choices[0].message.content = json.dumps(complete_recipe) |
117 | 154 | mock_response.model = "gpt-4o-mini" |
118 | 155 | mock_response.usage = Mock() |
119 | 156 | mock_response.usage.total_tokens = 100 |
@@ -171,8 +208,21 @@ def test_extract_with_caching(self, config): |
171 | 208 | with patch('structured_output_cookbook.extractor.OpenAI'): |
172 | 209 | extractor = StructuredExtractor(config) |
173 | 210 |
|
174 | | - # Mock cache hit |
175 | | - cached_data = {"name": "Cached Recipe", "ingredients": [], "instructions": []} |
| 211 | + # Mock cache hit with complete data |
| 212 | + cached_data = { |
| 213 | + "name": "Cached Recipe", |
| 214 | + "description": "A cached recipe", |
| 215 | + "cuisine": None, |
| 216 | + "difficulty": None, |
| 217 | + "prep_time": None, |
| 218 | + "cook_time": None, |
| 219 | + "total_time": None, |
| 220 | + "servings": None, |
| 221 | + "ingredients": [], |
| 222 | + "instructions": [], |
| 223 | + "tags": [], |
| 224 | + "nutrition": None |
| 225 | + } |
176 | 226 | if extractor.cache: |
177 | 227 | extractor.cache.get = Mock(return_value=cached_data) |
178 | 228 |
|
|
0 commit comments