33
44from examples .advanced_operations .get_ad_group_bid_modifiers import main
55
6+ # --- Helper Mock Class ---
7+ class MockAdGroupBidModifierModel :
8+ def __init__ (self , client_enums ):
9+ # Attributes accessed directly by the script's print statement
10+ self .criterion_id = MagicMock (name = "criterion_id" )
11+ self .bid_modifier = MagicMock (name = "bid_modifier" )
12+
13+ self .device = MagicMock (name = "device_criterion" )
14+ # Ensure type_ itself can have .name called on it
15+ self .device .type_ = MagicMock (name = "device_type_enum_value" )
16+ self .device .type_ .name = "UNKNOWN_DEVICE" # Default .name for the enum value
17+
18+ # Hotel criteria attributes
19+ self .hotel_date_selection_type = MagicMock (name = "hotel_date_selection_type_criterion" )
20+ self .hotel_date_selection_type .type_ = MagicMock (name = "hotel_date_selection_type_enum_value" )
21+ self .hotel_date_selection_type .type_ .name = "UNKNOWN_HOTEL_DATE_SELECTION"
22+
23+ self .hotel_advance_booking_window = MagicMock (name = "hotel_advance_booking_window_criterion" )
24+ self .hotel_advance_booking_window .min_days = None
25+ self .hotel_advance_booking_window .max_days = None
26+
27+ self .hotel_length_of_stay = MagicMock (name = "hotel_length_of_stay_criterion" )
28+ self .hotel_length_of_stay .min_nights = None
29+ self .hotel_length_of_stay .max_nights = None
30+
31+ self .hotel_check_in_day = MagicMock (name = "hotel_check_in_day_criterion" )
32+ self .hotel_check_in_day .day_of_week = MagicMock (name = "day_of_week_enum_value" )
33+ self .hotel_check_in_day .day_of_week .name = "UNSPECIFIED_DAY"
34+
35+ self .hotel_check_in_date_range = MagicMock (name = "hotel_check_in_date_range_criterion" )
36+ self .hotel_check_in_date_range .start_date = None
37+ self .hotel_check_in_date_range .end_date = None
38+
39+ # This will store the name of the 'oneof' criterion field (e.g., "device")
40+ self ._active_criterion_field = None # Default to None, must be set by test
41+
42+ @classmethod
43+ def pb (cls , instance_self ):
44+ mock_pb_message = MagicMock (name = "pb_message" )
45+ mock_pb_message .WhichOneof .return_value = instance_self ._active_criterion_field
46+ return mock_pb_message
47+
48+ def set_active_criterion_field (self , field_name ):
49+ self ._active_criterion_field = field_name
50+ # Basic way to somewhat mimic oneof: clear other fields if one is set.
51+ # More robust would be to ensure only the active field has a non-default/non-None value.
52+ # For this mock, primarily WhichOneof matters for the script's logic.
53+ all_criteria_fields = [
54+ "device" , "hotel_date_selection_type" , "hotel_advance_booking_window" ,
55+ "hotel_length_of_stay" , "hotel_check_in_day" , "hotel_check_in_date_range"
56+ ]
57+ if field_name not in all_criteria_fields and field_name is not None :
58+ raise ValueError (f"Unknown criterion field: { field_name } " )
59+ return self
60+
61+ # --- Test Functions ---
662def test_main_runs_successfully (mock_google_ads_client : MagicMock ) -> None :
763 """Tests that the main function runs without raising an exception with an ad_group_id."""
864 mock_customer_id = "123"
965 mock_ad_group_id = "456"
1066
11- # Mock GoogleAdsService for search
67+ # --- Mock Enums (ensure they have .name attribute) ---
68+ mock_google_ads_client .enums .DeviceEnum .MOBILE .name = "MOBILE_DEVICE"
69+ mock_google_ads_client .enums .DeviceEnum .TABLET .name = "TABLET_DEVICE" # Just in case
70+ mock_google_ads_client .enums .DeviceEnum .DESKTOP .name = "DESKTOP_DEVICE" # Just in case
71+ mock_google_ads_client .enums .DeviceEnum .UNKNOWN .name = "UNKNOWN_DEVICE" # Default
72+
73+ mock_google_ads_client .enums .DayOfWeekEnum .MONDAY .name = "MONDAY"
74+ mock_google_ads_client .enums .DayOfWeekEnum .UNSPECIFIED .name = "UNSPECIFIED_DOW" # Default
75+
76+ # Add other hotel enums if specific paths are tested, e.g., HotelDateSelectionTypeEnum
77+ mock_google_ads_client .enums .HotelDateSelectionTypeEnum .DEFAULT_SELECTION .name = "DEFAULT_SELECTION"
78+ mock_google_ads_client .enums .HotelDateSelectionTypeEnum .UNKNOWN .name = "UNKNOWN_HDST" # Default
79+
80+ # --- Mock GoogleAdsService for search ---
1281 mock_googleads_service = mock_google_ads_client .get_service ("GoogleAdsService" )
1382
14- mock_search_response_page = MagicMock () # Represents one page of results
83+ # Row 1: Device Modifier
1584 mock_row1 = MagicMock ()
16- mock_row1 .ad_group_bid_modifier .criterion_id = 12345
17- mock_row1 .ad_group_bid_modifier .bid_modifier = 1.5
18- mock_row1 .ad_group_bid_modifier .device .type_ = mock_google_ads_client .enums .DeviceEnum .MOBILE
85+ modifier1 = MockAdGroupBidModifierModel (mock_google_ads_client .enums )
86+ modifier1 .criterion_id = "1001"
87+ modifier1 .bid_modifier = 1.5
88+ modifier1 .set_active_criterion_field ("device" )
89+ modifier1 .device .type_ = mock_google_ads_client .enums .DeviceEnum .MOBILE
90+ mock_row1 .ad_group_bid_modifier = modifier1
1991 mock_row1 .ad_group .id = int (mock_ad_group_id )
20- mock_row1 .campaign .id = 789
21-
22- mock_row2 = MagicMock () # Example for a non-device modifier (e.g. hotel)
23- mock_row2 . ad_group_bid_modifier . criterion_id = 67890
24- mock_row2 . ad_group_bid_modifier . bid_modifier = 0.8
25- # For hotel check-in day, the device field won't be populated.
26- # Instead, hotel_check_in_day field would be, for example:
27- mock_row2 . ad_group_bid_modifier . hotel_check_in_day . day_of_week = mock_google_ads_client . enums . DayOfWeekEnum . MONDAY
28- # Clear other oneof fields like device for this specific row if the script checks for their absence
29- delattr ( mock_row2 .ad_group_bid_modifier , 'device' )
92+ mock_row1 .campaign .id = " 789"
93+
94+ # Row 2: Hotel Check-in Day Modifier
95+ mock_row2 = MagicMock ()
96+ modifier2 = MockAdGroupBidModifierModel ( mock_google_ads_client . enums )
97+ modifier2 . criterion_id = "2002"
98+ modifier2 . bid_modifier = 0.8
99+ modifier2 . set_active_criterion_field ( " hotel_check_in_day" )
100+ modifier2 . hotel_check_in_day . day_of_week = mock_google_ads_client . enums . DayOfWeekEnum . MONDAY
101+ mock_row2 .ad_group_bid_modifier = modifier2
30102 mock_row2 .ad_group .id = int (mock_ad_group_id )
31- mock_row2 .campaign .id = 789
103+ mock_row2 .campaign .id = "790"
32104
105+ mock_search_response_page = MagicMock ()
33106 mock_search_response_page .results = [mock_row1 , mock_row2 ]
34- # The search method returns an iterable of pages (MagicMock with results)
35107 mock_googleads_service .search .return_value = iter ([mock_search_response_page ])
36108
37- # Ensure enums used in results and script are available (DeviceEnum, DayOfWeekEnum)
38- # These should be on mock_google_ads_client.enums from conftest.
39- # e.g. mock_google_ads_client.enums.DeviceEnum.MOBILE
40- # e.g. mock_google_ads_client.enums.DayOfWeekEnum.MONDAY
41-
42109 try :
43110 main (
44111 mock_google_ads_client ,
@@ -51,18 +118,28 @@ def test_main_runs_successfully(mock_google_ads_client: MagicMock) -> None:
51118def test_main_runs_without_ad_group_id (mock_google_ads_client : MagicMock ) -> None :
52119 """Tests that the main function runs without an ad_group_id (fetches for all ad groups)."""
53120 mock_customer_id = "123"
54- mock_ad_group_id = None
121+ mock_ad_group_id = None # Key difference for this test
122+
123+ # --- Mock Enums (ensure they have .name attribute) ---
124+ # Ensure these are available on the mock_google_ads_client.enums object
125+ # The conftest should provide the base enums, we just need to ensure .name is on values.
126+ mock_google_ads_client .enums .DeviceEnum .TABLET .name = "TABLET_DEVICE"
127+ mock_google_ads_client .enums .DeviceEnum .UNKNOWN .name = "UNKNOWN_DEVICE"
55128
129+ # --- Mock GoogleAdsService for search ---
56130 mock_googleads_service = mock_google_ads_client .get_service ("GoogleAdsService" )
57131
58- mock_search_response_page = MagicMock ()
59132 mock_row1 = MagicMock ()
60- mock_row1 .ad_group_bid_modifier .criterion_id = 54321
61- mock_row1 .ad_group_bid_modifier .bid_modifier = 1.2
62- mock_row1 .ad_group_bid_modifier .device .type_ = mock_google_ads_client .enums .DeviceEnum .TABLET
63- mock_row1 .ad_group .id = 987 # Different ad group ID
64- mock_row1 .campaign .id = 654
133+ modifier1 = MockAdGroupBidModifierModel (mock_google_ads_client .enums )
134+ modifier1 .criterion_id = "3003"
135+ modifier1 .bid_modifier = 1.2
136+ modifier1 .set_active_criterion_field ("device" )
137+ modifier1 .device .type_ = mock_google_ads_client .enums .DeviceEnum .TABLET
138+ mock_row1 .ad_group_bid_modifier = modifier1
139+ mock_row1 .ad_group .id = "987" # Different ad group ID
140+ mock_row1 .campaign .id = "654"
65141
142+ mock_search_response_page = MagicMock ()
66143 mock_search_response_page .results = [mock_row1 ]
67144 mock_googleads_service .search .return_value = iter ([mock_search_response_page ])
68145
0 commit comments