Skip to content

Commit 609d939

Browse files
fix(tests): Resolve UnboundLocalError in test_add_smart_campaign.py
Ensured that `mock_ktc_service` (and other service mocks) are initialized by calling `mock_google_ads_client.get_service(...)` before any attributes are accessed or methods configured on them. This fixes the `UnboundLocalError` previously occurring in both test functions within `test_add_smart_campaign.py`.
1 parent 4fa20c7 commit 609d939

File tree

1 file changed

+65
-11
lines changed

1 file changed

+65
-11
lines changed

examples/advanced_operations/tests/test_add_smart_campaign.py

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,28 +114,53 @@ def new_get_type_side_effect_main(type_name):
114114
mock_google_ads_client.get_type.side_effect = new_get_type_side_effect_main
115115
# --- End of client.get_type mocking ---
116116

117-
# Refined SmartCampaignSuggestService.suggest_keyword_themes mock
117+
# --- Mock services ---
118+
mock_suggest_service = mock_google_ads_client.get_service("SmartCampaignSuggestService")
119+
mock_ktc_service = mock_google_ads_client.get_service("KeywordThemeConstantService") # Define mock_ktc_service
120+
mock_geo_service = mock_google_ads_client.get_service("GeoTargetConstantService")
121+
mock_googleads_service = mock_google_ads_client.get_service("GoogleAdsService")
122+
123+
# Configure mock_suggest_service
118124
# This is called by _get_keyword_theme_infos for free_form_keyword_text
119125
mock_suggest_themes_response_main = MagicMock()
120126
free_form_theme_instance = create_mock_keyword_theme_instance_func()
121127
free_form_theme_instance.free_form_keyword_theme = "mocked free form text" # From free_form_keyword_text
122128
mock_suggest_themes_response_main.keyword_themes = [free_form_theme_instance]
123-
# The side_effect for suggest_keyword_themes needs to handle different request types if script calls it multiple ways.
124-
# For free_form_text path:
125129
mock_suggest_service.suggest_keyword_themes.return_value = mock_suggest_themes_response_main
126-
# If suggest_keyword_themes was also called for keyword_seed (it's not, suggest_keyword_theme_constants is),
127-
# the side_effect would need to distinguish. Since it's only for free_form_text:
128-
# Simplified: if called, it's for free_form_text.
129130

130-
# Refined KeywordThemeConstantService.suggest_keyword_theme_constants mock
131+
# Configure mock_ktc_service
131132
# This is called by _get_keyword_theme_auto_suggestions for keyword_text
132133
mock_ktc_response_main = MagicMock()
133134
ktc_proto_mock_main = MagicMock() # Simulates KeywordThemeConstant proto
134135
ktc_proto_mock_main.resource_name = "keywordThemeConstants/from_text_search_auto1"
135136
mock_ktc_response_main.keyword_theme_constants = [ktc_proto_mock_main]
136137
mock_ktc_service.suggest_keyword_theme_constants.return_value = mock_ktc_response_main
138+
mock_ktc_service.keyword_theme_constant_path.side_effect = lambda ktc_id: f"keywordThemeConstants/{ktc_id}" # Path mock
139+
140+
# Configure mock_geo_service
141+
mock_geo_service.geo_target_constant_path.return_value = "geoTargetConstants/2840" # USA
142+
143+
# Configure mock_googleads_service (paths and mutate)
144+
mock_googleads_service.campaign_budget_path.return_value = f"customers/{mock_customer_id}/campaignBudgets/{_BUDGET_TEMPORARY_ID}"
145+
mock_googleads_service.campaign_path.return_value = f"customers/{mock_customer_id}/campaigns/{_SMART_CAMPAIGN_TEMPORARY_ID}"
146+
mock_googleads_service.ad_group_path.return_value = f"customers/{mock_customer_id}/adGroups/{_AD_GROUP_TEMPORARY_ID}"
147+
# business_profile_location_path mock (not used in this test path as mock_business_profile_location is None)
148+
if mock_business_profile_location: # Should be None for this test
149+
mock_googleads_service.business_profile_location_path.return_value = f"businessProfileLocations/{mock_business_profile_location.split('/')[-1]}"
150+
# Mutate call mock
151+
mock_mutate_response = MagicMock()
152+
responses = []
153+
responses.append(MagicMock(campaign_budget_result=MagicMock(resource_name=f"customers/{mock_customer_id}/campaignBudgets/budget1")))
154+
responses.append(MagicMock(campaign_result=MagicMock(resource_name=f"customers/{mock_customer_id}/campaigns/campaign1")))
155+
responses.append(MagicMock(smart_campaign_setting_result=MagicMock(resource_name=f"customers/{mock_customer_id}/smartCampaignSettings/scs1")))
156+
responses.append(MagicMock(ad_group_result=MagicMock(resource_name=f"customers/{mock_customer_id}/adGroups/adgroup1")))
157+
responses.append(MagicMock(ad_group_ad_result=MagicMock(resource_name=f"customers/{mock_customer_id}/adGroupAds/ad1")))
158+
for i in range(3):
159+
responses.append(MagicMock(campaign_criterion_result=MagicMock(resource_name=f"customers/{mock_customer_id}/campaignCriteria/crit{i}")))
160+
mock_mutate_response.mutate_operation_responses = responses
161+
mock_googleads_service.mutate.return_value = mock_mutate_response
137162

138-
# Suggest Budget Options (remains largely the same)
163+
# Suggest Budget Options (remains largely the same after service inits)
139164
mock_budget_options_response = MagicMock()
140165
mock_recommended_budget = MagicMock()
141166
mock_recommended_budget.daily_amount_micros = 50000000 # 50 units of currency
@@ -303,20 +328,49 @@ def new_get_type_side_effect_biz_func(type_name): # Unique name
303328
mock_google_ads_client.get_type.side_effect = new_get_type_side_effect_biz_func
304329
# --- End of client.get_type mocking for biz test ---
305330

306-
# Refined SmartCampaignSuggestService.suggest_keyword_themes mock for biz test
331+
# --- Mock services for biz test ---
332+
mock_suggest_service = mock_google_ads_client.get_service("SmartCampaignSuggestService")
333+
mock_ktc_service = mock_google_ads_client.get_service("KeywordThemeConstantService") # Define mock_ktc_service
334+
mock_geo_service = mock_google_ads_client.get_service("GeoTargetConstantService")
335+
mock_googleads_service = mock_google_ads_client.get_service("GoogleAdsService")
336+
337+
# Configure mock_suggest_service for biz test
307338
# free_form_keyword_text is None, so _get_keyword_theme_infos won't call suggest_keyword_themes for it.
308339
mock_suggest_themes_response_biz = MagicMock()
309340
mock_suggest_themes_response_biz.keyword_themes = [] # No themes from this call path
310341
mock_suggest_service.suggest_keyword_themes.return_value = mock_suggest_themes_response_biz
311342

312-
# Refined KeywordThemeConstantService.suggest_keyword_theme_constants mock for biz test
343+
# Configure mock_ktc_service for biz test
313344
mock_ktc_response_biz = MagicMock()
314345
ktc_proto_mock_biz = MagicMock()
315346
ktc_proto_mock_biz.resource_name = "keywordThemeConstants/from_text_search_auto_biz"
316347
mock_ktc_response_biz.keyword_theme_constants = [ktc_proto_mock_biz]
317348
mock_ktc_service.suggest_keyword_theme_constants.return_value = mock_ktc_response_biz
349+
mock_ktc_service.keyword_theme_constant_path.side_effect = lambda ktc_id: f"keywordThemeConstants/{ktc_id}" # Path mock
350+
351+
# Configure mock_geo_service
352+
mock_geo_service.geo_target_constant_path.return_value = "geoTargetConstants/2840" # USA
353+
354+
# Configure mock_googleads_service (paths and mutate)
355+
mock_googleads_service.campaign_budget_path.return_value = f"customers/{mock_customer_id}/campaignBudgets/{_BUDGET_TEMPORARY_ID}"
356+
mock_googleads_service.campaign_path.return_value = f"customers/{mock_customer_id}/campaigns/{_SMART_CAMPAIGN_TEMPORARY_ID}"
357+
mock_googleads_service.ad_group_path.return_value = f"customers/{mock_customer_id}/adGroups/{_AD_GROUP_TEMPORARY_ID}"
358+
if mock_business_profile_location: # Should be set for this test
359+
mock_googleads_service.business_profile_location_path.return_value = mock_business_profile_location
360+
# Mutate call mock
361+
mock_mutate_response_biz = MagicMock() # Distinct name for clarity
362+
responses_biz = []
363+
responses_biz.append(MagicMock(campaign_budget_result=MagicMock(resource_name=f"customers/{mock_customer_id}/campaignBudgets/budget_biz")))
364+
responses_biz.append(MagicMock(campaign_result=MagicMock(resource_name=f"customers/{mock_customer_id}/campaigns/campaign_biz")))
365+
responses_biz.append(MagicMock(smart_campaign_setting_result=MagicMock(resource_name=f"customers/{mock_customer_id}/smartCampaignSettings/scs_biz")))
366+
responses_biz.append(MagicMock(ad_group_result=MagicMock(resource_name=f"customers/{mock_customer_id}/adGroups/adgroup_biz")))
367+
responses_biz.append(MagicMock(ad_group_ad_result=MagicMock(resource_name=f"customers/{mock_customer_id}/adGroupAds/ad_biz")))
368+
for i in range(2):
369+
responses_biz.append(MagicMock(campaign_criterion_result=MagicMock(resource_name=f"customers/{mock_customer_id}/campaignCriteria/crit_biz{i}")))
370+
mock_mutate_response_biz.mutate_operation_responses = responses_biz
371+
mock_googleads_service.mutate.return_value = mock_mutate_response_biz
318372

319-
# Suggest Budget Options (remains largely the same)
373+
# Suggest Budget Options (remains largely the same after service inits)
320374
mock_recommended_budget = MagicMock()
321375
mock_recommended_budget.daily_amount_micros = 55000000
322376
mock_budget_options_response.recommended_daily_budget_options.high.daily_amount_micros = 65000000

0 commit comments

Comments
 (0)