import logging from unittest.mock import MagicMock, patch import pytest from src import controller from src.config.objects import (FetchTargetObjects, LastFetchDatetime, TargetObject) from src.error.exceptions import MeDaCaCRMDataFetchException from src.system_var.constants import PRE_JP_NAME from src.util.execute_datetime import ExecuteDateTime from .test_utils.log_message import generate_log_message_tuple EXPECT_PROCESS_RESULT = { 'Account': 'success', 'Contact': 'success', 'Call2_vod__c': 'success' } class ForTestControllerException(MeDaCaCRMDataFetchException): pass class TestController: @pytest.fixture() def call_all_processes(self, s3_client, monkeypatch, caplog): """ コントロール処理内ですべてのプロセス関数が呼ばれることのテストで使用するフィクスチャ 各種プロセス関数をモック化し、正常終了させるように動く Yields: dict: プロセス関数呼び出し後のモックの辞書 """ def _func(): monkeypatch.setattr(FetchTargetObjects, '_FetchTargetObjects__validate', lambda x: None) monkeypatch.setattr(TargetObject, '_TargetObject__validate', lambda x: None) monkeypatch.setattr(LastFetchDatetime, '_LastFetchDatetime__validate', lambda x: None) mock_execute_datetime = ExecuteDateTime() objects = { 'objects': [ { 'object_name': 'Account', 'upload_file_name': 'Account_YYYYMMDDHHMMSS' }, { 'object_name': 'Contact', 'upload_file_name': 'Contact_YYYYMMDDHHMMSS' }, { 'object_name': 'Call2_vod__c', 'upload_file_name': 'Call2_vod__c_YYYYMMDDHHMMSS' } ] } mock_target_objects = FetchTargetObjects(objects) mock_target_object_first = TargetObject(objects['objects'][0], mock_execute_datetime) mock_target_object_second = TargetObject(objects['objects'][1], mock_execute_datetime) mock_target_object_third = TargetObject(objects['objects'][2], mock_execute_datetime) mock_return_values = [mock_target_object_first, mock_target_object_second, mock_target_object_third] mock_last_fetch_datetime = LastFetchDatetime({ 'last_fetch_datetime_from': '1900-01-01T00:00:00.000Z', 'last_fetch_datetime_to': '9999-12-31T59:59:59.000Z' }, mock_execute_datetime) mock_prepare_data_fetch_process = MagicMock(return_value=(mock_target_objects, mock_execute_datetime, {})) mock_check_object_info_process = MagicMock(side_effect=mock_return_values) mock_set_datetime_period_process = MagicMock(return_value=mock_last_fetch_datetime) mock_fetch_crm_data_process = MagicMock(return_value=[{}]) mock_backup_crm_data_process = MagicMock() mock_convert_crm_csv_data_process = MagicMock() mock_backup_crm_csv_data_process = MagicMock() mock_copy_crm_csv_data_process = MagicMock() mock_upload_last_fetch_datetime_process = MagicMock() mock_upload_result_data_process = MagicMock() should_call_processes = { 'prepare_data_fetch_process': mock_prepare_data_fetch_process, 'check_object_info_process': mock_check_object_info_process, 'set_datetime_period_process': mock_set_datetime_period_process, 'fetch_crm_data_process': mock_fetch_crm_data_process, 'backup_crm_data_process': mock_backup_crm_data_process, 'convert_crm_csv_data_process': mock_convert_crm_csv_data_process, 'backup_crm_csv_data_process': mock_backup_crm_csv_data_process, 'copy_crm_csv_data_process': mock_copy_crm_csv_data_process, 'upload_last_fetch_datetime_process': mock_upload_last_fetch_datetime_process, 'upload_result_data_process': mock_upload_result_data_process } with patch('src.controller.prepare_data_fetch_process', mock_prepare_data_fetch_process),\ patch('src.controller.check_object_info_process', mock_check_object_info_process),\ patch('src.controller.set_datetime_period_process', mock_set_datetime_period_process),\ patch('src.controller.fetch_crm_data_process', mock_fetch_crm_data_process),\ patch('src.controller.backup_crm_data_process', mock_backup_crm_data_process),\ patch('src.controller.convert_crm_csv_data_process', mock_convert_crm_csv_data_process),\ patch('src.controller.backup_crm_csv_data_process', mock_backup_crm_csv_data_process),\ patch('src.controller.copy_crm_csv_data_process', mock_copy_crm_csv_data_process),\ patch('src.controller.upload_last_fetch_datetime_process', mock_upload_last_fetch_datetime_process),\ patch('src.controller.upload_result_data_process', mock_upload_result_data_process): controller.controller() return should_call_processes yield _func def test_call_all_processes(self, call_all_processes): """ Cases: コントロール処理からすべてのプロセスが呼ばれること Arranges: - call_all_processesフィクスチャで、コントロール処理を実行しておく Expects: - データ取得準備処理が1回のみ実行される - オブジェクト情報形式チェック処理が複数回実行される - データ取得期間設定処理が複数回実行される - CRMデータ取得処理が複数回実行される - CRM電文データバックアップ処理が複数回実行される - CSV変換処理が複数回実行される - CSVバックアップ処理が複数回実行される - CSVアップロード処理が複数回実行される - 前回取得日時ファイル更新処理が複数回実行される - 取得処理実施結果アップロード処理が1回のみ実行される """ processes = call_all_processes() processes['prepare_data_fetch_process'].assert_called_once(), 'データ取得準備処理が1回のみ実行されること' assert processes['check_object_info_process'].call_count == 3, 'オブジェクト情報形式チェック処理が複数回実行されること' assert processes['set_datetime_period_process'].call_count == 3, 'データ取得期間設定処理が複数回実行されること' assert processes['fetch_crm_data_process'].call_count == 3, 'CRMデータ取得処理が複数回実行されること' assert processes['backup_crm_data_process'].call_count == 3, 'CRM電文データバックアップ処理が複数回実行されること' assert processes['convert_crm_csv_data_process'].call_count == 3, 'CSV変換処理が複数回実行されること' assert processes['backup_crm_csv_data_process'].call_count == 3, 'CSVバックアップ処理が複数回実行されること' assert processes['copy_crm_csv_data_process'].call_count == 3, 'CSVアップロード処理が複数回実行されること' assert processes['upload_last_fetch_datetime_process'].call_count == 3, '前回取得日次ファイル更新処理が複数回実行されること' processes['upload_result_data_process'].assert_called_once(), '取得処理実施結果アップロード処理が1回のみ実行されること' def test_print_normal_logs(self, call_all_processes, caplog): """ Cases: コントロール処理の正常系ログがすべての出力されていること Arranges: - call_all_processesフィクスチャで、コントロール処理を実行しておく Expects: - コントロール処理の正常系ログがすべて出力されている """ call_all_processes() assert generate_log_message_tuple(log_message='I-CTRL-01 CRMデータ取得処理を開始します') in caplog.record_tuples assert generate_log_message_tuple(log_message='I-CTRL-02 データ取得準備処理呼び出し') in caplog.record_tuples assert generate_log_message_tuple(log_message='I-CTRL-03 取得対象オブジェクトのループ処理開始') in caplog.record_tuples for name in ['Account', 'Contact', 'Call2_vod__c']: object_name = name upload_file_name = f'{name}_YYYYMMDDHHMMSS' assert generate_log_message_tuple(log_message='I-CTRL-05 オブジェクト情報形式チェック処理呼び出し') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-06 [{object_name}]のデータ取得を開始します') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-08 [{object_name}]のデータ取得期間設定処理呼び出し') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-09 [{object_name}]のデータ取得処理呼び出し') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-10 [{object_name}] の出力ファイル名は [{upload_file_name}] となります') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-11 [{object_name}] CRM電文データバックアップ処理呼び出し') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-12 [{object_name}] CSV変換処理呼び出し') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-13 [{object_name}] CSVデータバックアップ処理呼び出し') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-14 [{object_name}] CSVデータアップロード処理呼び出し') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-15 [{object_name}] 前回取得日時ファイル更新処理呼び出し') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-16 [{object_name}] 処理正常終了') in caplog.record_tuples expect_process_result = { 'Account': 'success', 'Contact': 'success', 'Call2_vod__c': 'success' } assert generate_log_message_tuple(log_message=f'I-CTRL-17 すべてのオブジェクトの処理が終了しました 実行結果:[{expect_process_result}]') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-18 CRM_取得処理実施結果ファイルアップロード処理開始') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-19 すべてのデータの取得に成功しました') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-20 CRMデータ取得処理を終了します') in caplog.record_tuples def test_do_not_call_upload_process_result_process(self, s3_client, monkeypatch, caplog): """ Cases: 処理対象オブジェクトが0件の場合、取得処理実施結果アップロード処理が実行されないこと Arranges: - データ取得準備処理で返される取得対象オブジェクト情報を0件にする - 各種プロセスメソッドと内部で使用している値オブジェクトをモック化する Expects: - データ取得準備処理が1回のみ実行されること - 取得処理実施結果アップロード処理が実行されないこと - 処理対象が存在しない旨を示すログメッセージが出力されていること """ mock_execute_datetime = ExecuteDateTime() mock_prepare_data_fetch_process = MagicMock(return_value=([], mock_execute_datetime, {})) mock_check_object_info_process = MagicMock() mock_set_datetime_period_process = MagicMock() mock_fetch_crm_data_process = MagicMock() mock_backup_crm_data_process = MagicMock() mock_convert_crm_csv_data_process = MagicMock() mock_backup_crm_csv_data_process = MagicMock() mock_copy_crm_csv_data_process = MagicMock() mock_upload_last_fetch_datetime_process = MagicMock() mock_upload_result_data_process = MagicMock() with patch('src.controller.prepare_data_fetch_process', mock_prepare_data_fetch_process),\ patch('src.controller.check_object_info_process', mock_check_object_info_process),\ patch('src.controller.set_datetime_period_process', mock_set_datetime_period_process),\ patch('src.controller.fetch_crm_data_process', mock_fetch_crm_data_process),\ patch('src.controller.backup_crm_data_process', mock_backup_crm_data_process),\ patch('src.controller.convert_crm_csv_data_process', mock_convert_crm_csv_data_process),\ patch('src.controller.backup_crm_csv_data_process', mock_backup_crm_csv_data_process),\ patch('src.controller.copy_crm_csv_data_process', mock_copy_crm_csv_data_process),\ patch('src.controller.upload_last_fetch_datetime_process', mock_upload_last_fetch_datetime_process),\ patch('src.controller.upload_result_data_process', mock_upload_result_data_process): controller.controller() # 実行回数の確認 mock_prepare_data_fetch_process.assert_called_once(), 'データ取得準備処理が1回のみ実行されること' mock_upload_result_data_process.call_count == 0, '取得処理実施結果アップロード処理が実行されないこと' # ログ出力の確認 assert generate_log_message_tuple(log_message='I-CTRL-21 処理対象のデータが存在しませんでした') in caplog.record_tuples, '処理対象が存在しない旨を示すログメッセージが出力されていること' assert generate_log_message_tuple(log_message=f'I-CTRL-20 CRMデータ取得処理を終了します') in caplog.record_tuples def test_do_not_call_upload_csv_process(self, s3_client, monkeypatch, caplog): """ Cases: オブジェクト情報.is_skipがTrueの場合、CSVアップロード処理が実行されないこと Arranges: - データ取得準備処理で返される取得対象オブジェクト情報のis_skipをTrueにする - 各種プロセスメソッドと内部で使用している値オブジェクトをモック化する Expects: - オブジェクト情報形式チェック処理以降のプロセスが実行されないこと - 処理をスキップする旨を示すログメッセージが出力されていること """ mock_check_object_info = { 'object_name': 'Account', 'is_skip': True } monkeypatch.setattr(TargetObject, '_TargetObject__validate', lambda x: None) mock_execute_datetime = ExecuteDateTime() mock_return_values = [TargetObject(mock_check_object_info, mock_execute_datetime)] mock_prepare_data_fetch_process = MagicMock(return_value=([mock_check_object_info], mock_execute_datetime, {})) mock_check_object_info_process = MagicMock(side_effect=mock_return_values) mock_set_datetime_period_process = MagicMock() mock_fetch_crm_data_process = MagicMock() mock_backup_crm_data_process = MagicMock() mock_convert_crm_csv_data_process = MagicMock() mock_backup_crm_csv_data_process = MagicMock() mock_copy_crm_csv_data_process = MagicMock() mock_upload_last_fetch_datetime_process = MagicMock() mock_upload_result_data_process = MagicMock() with patch('src.controller.prepare_data_fetch_process', mock_prepare_data_fetch_process),\ patch('src.controller.check_object_info_process', mock_check_object_info_process),\ patch('src.controller.set_datetime_period_process', mock_set_datetime_period_process),\ patch('src.controller.fetch_crm_data_process', mock_fetch_crm_data_process),\ patch('src.controller.backup_crm_data_process', mock_backup_crm_data_process),\ patch('src.controller.convert_crm_csv_data_process', mock_convert_crm_csv_data_process),\ patch('src.controller.backup_crm_csv_data_process', mock_backup_crm_csv_data_process),\ patch('src.controller.copy_crm_csv_data_process', mock_copy_crm_csv_data_process),\ patch('src.controller.upload_last_fetch_datetime_process', mock_upload_last_fetch_datetime_process),\ patch('src.controller.upload_result_data_process', mock_upload_result_data_process): controller.controller() # 実行回数の確認 mock_check_object_info_process.assert_called_once() # オブジェクト情報形式チェック処理以降のプロセスが実行されないこと mock_set_datetime_period_process.call_count == 0 mock_fetch_crm_data_process.call_count == 0 mock_backup_crm_data_process.call_count == 0 mock_convert_crm_csv_data_process.call_count == 0 mock_backup_crm_csv_data_process.call_count == 0 mock_copy_crm_csv_data_process.call_count == 0 mock_upload_last_fetch_datetime_process.call_count == 0 mock_upload_result_data_process.call_count == 0 # ログ出力の確認 assert generate_log_message_tuple(log_message='I-CTRL-07 [Account]のデータ取得処理をスキップします') in caplog.record_tuples assert generate_log_message_tuple(log_message=f'I-CTRL-20 CRMデータ取得処理を終了します') in caplog.record_tuples def test_do_not_call_upload_csv_process_of_part(self, s3_client, monkeypatch, caplog): """ Cases: オブジェクト情報.is_skipがTrueのものが含まれる場合、CSVアップロード処理が実行されないこと Arranges: - データ取得準備処理で返される取得対象オブジェクト情報のうち、2つ目をis_skipをTrueにする - 各種プロセスメソッドと内部で使用している値オブジェクトをモック化する Expects: - オブジェクト情報形式チェック処理が2回実行されること - 処理をスキップする旨を示すログメッセージが出力されていること - オブジェクト情報.is_skipがFalseのものはCSVアップロード処理のログメッセージが出力されていること """ mock_check_object_infos = { 'objects': [ { 'object_name': 'Account', 'is_skip': False }, { 'object_name': 'Contact', 'is_skip': True }, { 'object_name': 'Call2_vod__c', 'is_skip': False } ] } monkeypatch.setattr(FetchTargetObjects, '_FetchTargetObjects__validate', lambda x: None) monkeypatch.setattr(TargetObject, '_TargetObject__validate', lambda x: None) mock_execute_datetime = ExecuteDateTime() FetchTargetObjects(mock_check_object_infos) mock_return_values = [ TargetObject(mock_check_object_infos['objects'][0], mock_execute_datetime), TargetObject(mock_check_object_infos['objects'][1], mock_execute_datetime), TargetObject(mock_check_object_infos['objects'][2], mock_execute_datetime), ] mock_prepare_data_fetch_process = MagicMock(return_value=(FetchTargetObjects(mock_check_object_infos), mock_execute_datetime, {})) mock_check_object_info_process = MagicMock(side_effect=mock_return_values) mock_set_datetime_period_process = MagicMock() mock_fetch_crm_data_process = MagicMock() mock_backup_crm_data_process = MagicMock() mock_convert_crm_csv_data_process = MagicMock() mock_backup_crm_csv_data_process = MagicMock() mock_copy_crm_csv_data_process = MagicMock() mock_upload_last_fetch_datetime_process = MagicMock() mock_upload_result_data_process = MagicMock() with patch('src.controller.prepare_data_fetch_process', mock_prepare_data_fetch_process),\ patch('src.controller.check_object_info_process', mock_check_object_info_process),\ patch('src.controller.set_datetime_period_process', mock_set_datetime_period_process),\ patch('src.controller.fetch_crm_data_process', mock_fetch_crm_data_process),\ patch('src.controller.backup_crm_data_process', mock_backup_crm_data_process),\ patch('src.controller.convert_crm_csv_data_process', mock_convert_crm_csv_data_process),\ patch('src.controller.backup_crm_csv_data_process', mock_backup_crm_csv_data_process),\ patch('src.controller.copy_crm_csv_data_process', mock_copy_crm_csv_data_process),\ patch('src.controller.upload_last_fetch_datetime_process', mock_upload_last_fetch_datetime_process),\ patch('src.controller.upload_result_data_process', mock_upload_result_data_process): controller.controller() # 実行回数の確認 mock_check_object_info_process.call_count == 3 # オブジェクト情報形式チェック処理以降のプロセスが実行されないこと mock_set_datetime_period_process.call_count == 2 mock_fetch_crm_data_process.call_count == 2 mock_backup_crm_data_process.call_count == 2 mock_convert_crm_csv_data_process.call_count == 2 mock_backup_crm_csv_data_process.call_count == 2 mock_copy_crm_csv_data_process.call_count == 2 mock_upload_last_fetch_datetime_process.call_count == 2 mock_upload_result_data_process.call_count == 2 # ログ出力の確認 assert generate_log_message_tuple( log_message='I-CTRL-14 [Account] CSVデータアップロード処理呼び出し') in caplog.record_tuples, 'オブジェクト情報.is_skipがFalseのものはCSVアップロード処理のログメッセージが出力されていること' assert generate_log_message_tuple( log_message='I-CTRL-07 [Contact]のデータ取得処理をスキップします') in caplog.record_tuples, '処理をスキップする旨を示すログメッセージが出力されていること' assert generate_log_message_tuple( log_message='I-CTRL-14 [Call2_vod__c] CSVデータアップロード処理呼び出し' ) in caplog.record_tuples, 'オブジェクト情報.is_skipがFalseのものはCSVアップロード処理のログメッセージが出力されていること' assert generate_log_message_tuple(log_message=f'I-CTRL-20 CRMデータ取得処理を終了します') in caplog.record_tuples def test_raise_mock_prepare_data_fetch_process(self, s3_client, monkeypatch, caplog): """ Cases: データ取得準備処理でシステム例外が発生した場合、エラーで終了すること Arranges: - データ取得準備処理でシステム例外が発生するようにする Expects: - データ取得準備処理で例外が発生すること - データ取得準備処理で発生した例外のログメッセージが出力されていること """ # mock_check_object_infos = copy.deepcopy(TEST_OBJECT_INFO_LIST) # mock_check_object_infos['objects'][1]['is_skip'] = True # monkeypatch.setattr(FetchTargetObjects, '_FetchTargetObjects__validate', lambda x: None) # monkeypatch.setattr(TargetObject, '_TargetObject__validate', lambda x: None) # mock_execute_datetime = ExecuteDateTime() # FetchTargetObjects(mock_check_object_infos) # mock_return_values = [ # TargetObject(mock_check_object_infos['objects'][0], mock_execute_datetime), # TargetObject(mock_check_object_infos['objects'][1], mock_execute_datetime), # TargetObject(mock_check_object_infos['objects'][2], mock_execute_datetime), # ] expect_exception = ForTestControllerException('E-CHK-01', PRE_JP_NAME, '例外発生') mock_prepare_data_fetch_process = MagicMock(side_effect=expect_exception) mock_check_object_info_process = MagicMock() # mock_set_datetime_period_process = MagicMock() # mock_fetch_crm_data_process = MagicMock() # mock_backup_crm_data_process = MagicMock() # mock_convert_crm_csv_data_process = MagicMock() # mock_backup_crm_csv_data_process = MagicMock() # mock_copy_crm_csv_data_process = MagicMock() # mock_upload_last_fetch_datetime_process = MagicMock() # mock_upload_result_data_process = MagicMock() with patch('src.controller.prepare_data_fetch_process', mock_prepare_data_fetch_process),\ patch('src.controller.check_object_info_process', mock_check_object_info_process): # patch('src.controller.set_datetime_period_process', mock_set_datetime_period_process),\ # patch('src.controller.fetch_crm_data_process', mock_fetch_crm_data_process),\ # patch('src.controller.backup_crm_data_process', mock_backup_crm_data_process),\ # patch('src.controller.convert_crm_csv_data_process', mock_convert_crm_csv_data_process),\ # patch('src.controller.backup_crm_csv_data_process', mock_backup_crm_csv_data_process),\ # patch('src.controller.copy_crm_csv_data_process', mock_copy_crm_csv_data_process),\ # patch('src.controller.upload_last_fetch_datetime_process', mock_upload_last_fetch_datetime_process),\ # patch('src.controller.upload_result_data_process', mock_upload_result_data_process): with pytest.raises(MeDaCaCRMDataFetchException): controller.controller() assert mock_check_object_info_process.called is False assert generate_log_message_tuple( log_level=logging.ERROR, log_message=f'E-ERR-01 [{PRE_JP_NAME}]でエラーが発生したため、処理を終了します'), 'データ取得準備処理で発生した例外のログメッセージが出力されていること'