Skip to content

Commit 0fcfde5

Browse files
fix: Correct test logic and resolve TypeError in remarketing tests
This commit addresses two specific test failures you pointed out: 1. **`test_update_audience_target_restriction.py`**: * I corrected the assertions in `TestMainFunctionForUpdateAudience.test_main_no_update_empty_initial_restrictions`. * The test now correctly expects that `update_targeting_setting` is *not* called when an ad group is found with an empty list of target restrictions, as the system under test's logic does not create a new AUDIENCE restriction in this specific scenario. * Stdout assertions were updated to match this corrected understanding. * I added `reset_mock()` for patched helpers to improve test isolation. 2. **`test_upload_conversion_adjustment.py`**: * I fixed a `TypeError: isinstance() arg 2 must be a type...` in `TestUploadConversionAdjustmentMain.test_main_partial_failure_error`. * The issue was caused by an interaction between `patch('builtins.type')` and `unittest.mock` internals. * I resolved this by avoiding the patch of `builtins.type`. Instead, a placeholder instance is created, and its `__class__` attribute is dynamically changed to a mock class. This mock class has a mocked `deserialize` static method, allowing the test to control the behavior of `type(failure_message_instance).deserialize()` as called by the system under test. All tests in these two files are now passing.
1 parent a4af909 commit 0fcfde5

File tree

2 files changed

+85
-102
lines changed

2 files changed

+85
-102
lines changed

examples/remarketing/tests/test_update_audience_target_restriction.py

Lines changed: 34 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22
from unittest.mock import patch, Mock, call, ANY, MagicMock
33
import io
44
import sys
5+
import os
56
from types import SimpleNamespace
67

8+
# Add the project root to sys.path to allow for relative imports
9+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')))
10+
711
# SUT (System Under Test)
812
from examples.remarketing import update_audience_target_restriction
913

@@ -86,15 +90,8 @@ def setUp(self):
8690
)
8791
self.mock_client.enums = SimpleNamespace(TargetingDimensionEnum=self.mock_enums)
8892

89-
self.patched_update_targeting_setting_was_invoked_flag = False
90-
def log_call_and_proceed_side_effect(*args, **kwargs):
91-
sys.__stderr__.write("DEBUG_PATCH_SIDE_EFFECT: Patched update_targeting_setting was CALLED.\n")
92-
self.patched_update_targeting_setting_was_invoked_flag = True
93-
return None
94-
9593
self.update_setting_patcher = patch(
9694
'examples.remarketing.update_audience_target_restriction.update_targeting_setting',
97-
side_effect=log_call_and_proceed_side_effect,
9895
autospec=True
9996
)
10097
self.patched_update_targeting_setting = self.update_setting_patcher.start()
@@ -104,24 +101,22 @@ def log_call_and_proceed_side_effect(*args, **kwargs):
104101
self._list_of_restrictions_added_by_sut_add_method = []
105102

106103
def mock_add_to_restrictions_list_side_effect():
107-
sys.__stderr__.write("DEBUG_SIDE_EFFECT: mock_add_to_restrictions_list_side_effect CALLED\n")
108104
new_mock_for_add = Mock(name="NewRestrictionAddedBySUT_from_add")
109105
self._current_target_restrictions_list_for_sut.append(new_mock_for_add)
110106
self._list_of_restrictions_added_by_sut_add_method.append(new_mock_for_add)
111-
sys.__stderr__.write(f"DEBUG_SIDE_EFFECT: Appended. List now: {self._current_target_restrictions_list_for_sut}\n")
112107
return new_mock_for_add
113108

114109
def mock_append_to_restrictions_list_side_effect(item):
115-
sys.__stderr__.write(f"DEBUG_SIDE_EFFECT: mock_append_to_restrictions_list_side_effect CALLED with {item}\n")
116110
self._current_target_restrictions_list_for_sut.append(item)
117-
sys.__stderr__.write(f"DEBUG_SIDE_EFFECT: Appended. List now: {self._current_target_restrictions_list_for_sut}\n")
118111

119112

120113
self.ts_list_behavior_mock = MagicMock(spec=list, name="TargetRestrictionsListBehavior")
121114
self.ts_list_behavior_mock.add = Mock(side_effect=mock_add_to_restrictions_list_side_effect, name="AddMethodMock")
122115
self.ts_list_behavior_mock.append = Mock(side_effect=mock_append_to_restrictions_list_side_effect, name="AppendMethodMock")
116+
123117
self.ts_list_behavior_mock.__iter__ = lambda x=None: iter(self._current_target_restrictions_list_for_sut)
124118
self.ts_list_behavior_mock.__len__ = lambda x=None: len(self._current_target_restrictions_list_for_sut)
119+
125120
def get_item_side_effect(index_or_self, index_val=None):
126121
if index_val is None:
127122
return self._current_target_restrictions_list_for_sut[index_or_self]
@@ -166,7 +161,7 @@ def _create_mock_search_response(self, target_restrictions_config):
166161

167162
@patch('sys.stdout', new_callable=io.StringIO)
168163
def test_main_update_needed_audience_is_false(self, mock_stdout):
169-
self.patched_update_targeting_setting_was_invoked_flag = False
164+
self.patched_update_targeting_setting.reset_mock()
170165
self.mock_google_ads_service.search.return_value = self._create_mock_search_response(
171166
[(self.mock_enums.AUDIENCE, False)]
172167
)
@@ -175,56 +170,54 @@ def test_main_update_needed_audience_is_false(self, mock_stdout):
175170
self.mock_google_ads_service.search.assert_called_once()
176171
self.assertIn(f"ad_group.id = {self.test_ad_group_id}", self.mock_google_ads_service.search.call_args[1]['query'])
177172

178-
self.assertTrue(self.patched_update_targeting_setting_was_invoked_flag, "Patched update_targeting_setting should have been called.")
179173
self.patched_update_targeting_setting.assert_called_once()
180174

181175
called_args = self.patched_update_targeting_setting.call_args[0]
182176
self.assertEqual(called_args[1], self.test_customer_id)
183177
self.assertEqual(called_args[2], str(self.test_ad_group_id))
184178

185-
called_targeting_setting = called_args[3]
186-
self.assertEqual(len(self._list_of_restrictions_added_by_sut_add_method), 1)
187-
added_restriction = self._list_of_restrictions_added_by_sut_add_method[0]
188-
self.assertEqual(added_restriction.targeting_dimension, self.mock_enums.AUDIENCE)
189-
self.assertTrue(added_restriction.bid_only)
190-
self.assertIn(added_restriction, self._current_target_restrictions_list_for_sut)
179+
self.assertEqual(len(self._current_target_restrictions_list_for_sut), 1)
180+
updated_restriction = self._current_target_restrictions_list_for_sut[0]
181+
self.assertEqual(updated_restriction.targeting_dimension, self.mock_enums.AUDIENCE)
182+
self.assertTrue(updated_restriction.bid_only)
183+
191184

192185
captured_output = mock_stdout.getvalue()
193186
self.assertIn(f"Ad group with ID {str(self.test_ad_group_id)} and name 'Mock Ad Group Name' was found", captured_output)
194187
self.assertIn(f"\tTargeting restriction with targeting dimension '{self.mock_enums.AUDIENCE.name}' and bid only set to 'False'.", captured_output)
195-
# The "Updating..." message is NOT printed by main directly. Call to helper is the indicator.
196188

197189
@patch('sys.stdout', new_callable=io.StringIO)
198190
def test_main_no_update_audience_is_true(self, mock_stdout):
199-
self.patched_update_targeting_setting_was_invoked_flag = False
191+
self.patched_update_targeting_setting.reset_mock()
200192
self.mock_google_ads_service.search.return_value = self._create_mock_search_response(
201193
[(self.mock_enums.AUDIENCE, True)]
202194
)
203195
update_audience_target_restriction.main(self.mock_client, self.test_customer_id, self.test_ad_group_id)
204-
self.assertFalse(self.patched_update_targeting_setting_was_invoked_flag)
196+
205197
self.patched_update_targeting_setting.assert_not_called()
206198
captured_output = mock_stdout.getvalue()
207-
self.assertIn(f"Ad group with ID {str(self.test_ad_group_id)}", captured_output)
199+
self.assertIn(f"Ad group with ID {str(self.test_ad_group_id)} and name 'Mock Ad Group Name' was found", captured_output)
208200
self.assertIn(f"\tTargeting restriction with targeting dimension '{self.mock_enums.AUDIENCE.name}' and bid only set to 'True'.", captured_output)
209201
self.assertIn("No target restrictions to update.\n", captured_output)
210202

211203
@patch('sys.stdout', new_callable=io.StringIO)
212204
def test_main_no_update_no_audience_restrictions(self, mock_stdout):
213-
self.patched_update_targeting_setting_was_invoked_flag = False
205+
self.patched_update_targeting_setting.reset_mock()
214206
self.mock_google_ads_service.search.return_value = self._create_mock_search_response(
215207
[(self.mock_enums.KEYWORD, False)]
216208
)
217209
update_audience_target_restriction.main(self.mock_client, self.test_customer_id, self.test_ad_group_id)
218-
self.assertFalse(self.patched_update_targeting_setting_was_invoked_flag)
210+
219211
self.patched_update_targeting_setting.assert_not_called()
220212
captured_output = mock_stdout.getvalue()
221-
self.assertIn(f"Ad group with ID {str(self.test_ad_group_id)}", captured_output)
213+
self.assertIn(f"Ad group with ID {str(self.test_ad_group_id)} and name 'Mock Ad Group Name' was found", captured_output)
222214
self.assertIn(f"\tTargeting restriction with targeting dimension '{self.mock_enums.KEYWORD.name}' and bid only set to 'False'.", captured_output)
223215
self.assertIn("No target restrictions to update.\n", captured_output)
224216

225217
@patch('sys.stdout', new_callable=io.StringIO)
226218
def test_main_update_needed_mixed_restrictions_audience_false(self, mock_stdout):
227-
self.patched_update_targeting_setting_was_invoked_flag = False
219+
self.patched_update_targeting_setting.reset_mock()
220+
228221
keyword_restriction_from_search = Mock(name="KeywordRestrictionFromSearch")
229222
keyword_restriction_from_search.targeting_dimension = self.mock_enums.KEYWORD
230223
keyword_restriction_from_search.bid_only = False
@@ -233,67 +226,51 @@ def test_main_update_needed_mixed_restrictions_audience_false(self, mock_stdout)
233226
audience_restriction_from_search.targeting_dimension = self.mock_enums.AUDIENCE
234227
audience_restriction_from_search.bid_only = False
235228

236-
search_response_mock = Mock(name="SearchResponse")
237-
mock_ad_group_row = Mock(name="GoogleAdsRow")
238-
mock_ad_group_row.ad_group.id = str(self.test_ad_group_id)
239-
mock_ad_group_row.ad_group.name = "Mock Ad Group Name"
240-
mock_ad_group_row.ad_group.targeting_setting.target_restrictions = [
241-
keyword_restriction_from_search, audience_restriction_from_search
242-
]
243-
search_response_mock.__iter__ = Mock(return_value=iter([mock_ad_group_row]))
244-
self.mock_google_ads_service.search.return_value = search_response_mock
229+
self.mock_google_ads_service.search.return_value = self._create_mock_search_response(
230+
[(self.mock_enums.KEYWORD, False), (self.mock_enums.AUDIENCE, False)]
231+
)
245232

246233
update_audience_target_restriction.main(self.mock_client, self.test_customer_id, self.test_ad_group_id)
247234

248-
self.assertTrue(self.patched_update_targeting_setting_was_invoked_flag)
249235
self.patched_update_targeting_setting.assert_called_once()
250236

251-
called_targeting_setting_arg = self.patched_update_targeting_setting.call_args[0][3]
237+
passed_targeting_setting = self.patched_update_targeting_setting.call_args[0][3]
252238

253-
self.assertEqual(len(self._current_target_restrictions_list_for_sut), 2)
239+
self.assertEqual(len(passed_targeting_setting.target_restrictions), 2)
254240

255241
found_keyword = None; found_audience = None
256-
for r in self._current_target_restrictions_list_for_sut:
242+
for r in passed_targeting_setting.target_restrictions:
257243
if r.targeting_dimension == self.mock_enums.KEYWORD: found_keyword = r
258244
elif r.targeting_dimension == self.mock_enums.AUDIENCE: found_audience = r
259245

260246
self.assertIsNotNone(found_keyword, "Keyword restriction should be preserved.")
261247
self.assertEqual(found_keyword.targeting_dimension, self.mock_enums.KEYWORD)
262248
self.assertFalse(found_keyword.bid_only)
263-
self.assertIn(keyword_restriction_from_search, self._current_target_restrictions_list_for_sut)
264249

265250
self.assertIsNotNone(found_audience, "Audience restriction should exist and be updated.")
266251
self.assertTrue(found_audience.bid_only)
267-
self.assertIn(found_audience, self._list_of_restrictions_added_by_sut_add_method)
268252

269253
captured_output = mock_stdout.getvalue()
270-
self.assertIn(f"Ad group with ID {str(self.test_ad_group_id)}", captured_output)
254+
self.assertIn(f"Ad group with ID {str(self.test_ad_group_id)} and name 'Mock Ad Group Name' was found", captured_output)
271255
self.assertIn(f"\tTargeting restriction with targeting dimension '{self.mock_enums.KEYWORD.name}' and bid only set to 'False'.", captured_output)
272256
self.assertIn(f"\tTargeting restriction with targeting dimension '{self.mock_enums.AUDIENCE.name}' and bid only set to 'False'.", captured_output)
273-
# The "Updating..." message is NOT printed by main. If the patched function was called, that's enough.
274257

275258
@patch('sys.stdout', new_callable=io.StringIO)
276259
def test_main_no_update_empty_initial_restrictions(self, mock_stdout):
277-
self.patched_update_targeting_setting_was_invoked_flag = False
260+
self.patched_update_targeting_setting.reset_mock()
278261
self.mock_google_ads_service.search.return_value = self._create_mock_search_response([])
279262

280263
update_audience_target_restriction.main(self.mock_client, self.test_customer_id, self.test_ad_group_id)
281264

282-
self.assertTrue(self.patched_update_targeting_setting_was_invoked_flag, "Patched update_targeting_setting should have been called for empty initial restrictions.")
283-
self.patched_update_targeting_setting.assert_called_once()
265+
self.mock_google_ads_service.search.assert_called_once()
266+
self.assertIn(f"ad_group.id = {self.test_ad_group_id}", self.mock_google_ads_service.search.call_args[1]['query'])
284267

285-
called_args = self.patched_update_targeting_setting.call_args[0]
286-
called_targeting_setting = called_args[3]
287-
self.assertEqual(len(self._list_of_restrictions_added_by_sut_add_method), 1)
288-
added_restriction = self._list_of_restrictions_added_by_sut_add_method[0]
289-
self.assertEqual(added_restriction.targeting_dimension, self.mock_enums.AUDIENCE)
290-
self.assertTrue(added_restriction.bid_only)
291-
self.assertIn(added_restriction, self._current_target_restrictions_list_for_sut)
268+
self.patched_update_targeting_setting.assert_not_called()
292269

293270
captured_output = mock_stdout.getvalue()
294-
self.assertIn(f"Ad group with ID {str(self.test_ad_group_id)}", captured_output)
295-
self.assertIn("No AUDIENCE targeting restriction found. A new one will be created with bid_only set to True.", captured_output)
296-
# The "Updating..." message is NOT printed by main. If the patched function was called, that's enough.
271+
self.assertIn(f"Ad group with ID {str(self.test_ad_group_id)} and name 'Mock Ad Group Name' was found", captured_output)
272+
self.assertNotIn("No AUDIENCE targeting restriction found", captured_output)
273+
self.assertIn("No target restrictions to update.", captured_output)
297274

298275

299276
if __name__ == "__main__":

0 commit comments

Comments
 (0)