diff --git a/ecs/jskult-batch-daily/README.md b/ecs/jskult-batch-daily/README.md index 57ae474b..46d1c3b6 100644 --- a/ecs/jskult-batch-daily/README.md +++ b/ecs/jskult-batch-daily/README.md @@ -12,79 +12,207 @@ ## 環境構築 -- Pythonの構築 - - Merck_NewDWH開発2021のWiki、[Python環境構築](https://nds-tyo.backlog.com/alias/wiki/1874930)を参照 - - 「Pipenvの導入」までを行っておくこと - - 構築完了後、プロジェクト配下で以下のコマンドを実行し、Pythonの仮想環境を作成する - - `pipenv install --dev --python ` - - この手順で出力される仮想環境のパスは、後述するVSCodeの設定手順で使用するため、控えておく +- Python の構築 -- MySQLの環境構築 - - Windowsの場合、以下のリンクからダウンロードする + - Merck_NewDWH 開発 2021 の Wiki、[Python 環境構築](https://nds-tyo.backlog.com/alias/wiki/1874930)を参照 + - 「Pipenv の導入」までを行っておくこと + - 構築完了後、プロジェクト配下で以下のコマンドを実行し、Python の仮想環境を作成する + - `pipenv install --dev --python ` + - この手順で出力される仮想環境のパスは、後述する VSCode の設定手順で使用するため、控えておく + +- MySQL の環境構築 + - Windows の場合、以下のリンクからダウンロードする - - - Dockerを利用する場合、「newsdwh-tools」リポジトリのMySQL設定を使用すると便利 + - Docker を利用する場合、「newsdwh-tools」リポジトリの MySQL 設定を使用すると便利 - 「crm-table-to-ddl」フォルダ内で以下のコマンドを実行すると - `docker-compose up -d` - - Dockerの構築手順は、[Dockerのセットアップ手順](https://nds-tyo.backlog.com/alias/wiki/1754332)を参照のこと + - Docker の構築手順は、[Docker のセットアップ手順](https://nds-tyo.backlog.com/alias/wiki/1754332)を参照のこと - データを投入する - 立ち上げたデータベースに「src05」スキーマを作成する - - [ローカル開発用データ](https://ndstokyo.sharepoint.com/:f:/r/sites/merck-new-dwh-team/Shared%20Documents/03.NewDWH%E6%A7%8B%E7%AF%89%E3%83%95%E3%82%A7%E3%83%BC%E3%82%BA3/02.%E9%96%8B%E7%99%BA/90.%E9%96%8B%E7%99%BA%E5%85%B1%E6%9C%89/%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E9%96%8B%E7%99%BA%E7%94%A8%E3%83%87%E3%83%BC%E3%82%BF?csf=1&web=1&e=VVcRUs)をダウンロードし、mysqlコマンドを使用して復元する + - [ローカル開発用データ](https://ndstokyo.sharepoint.com/:f:/r/sites/merck-new-dwh-team/Shared%20Documents/03.NewDWH%E6%A7%8B%E7%AF%89%E3%83%95%E3%82%A7%E3%83%BC%E3%82%BA3/02.%E9%96%8B%E7%99%BA/90.%E9%96%8B%E7%99%BA%E5%85%B1%E6%9C%89/%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E9%96%8B%E7%99%BA%E7%94%A8%E3%83%87%E3%83%BC%E3%82%BF?csf=1&web=1&e=VVcRUs)をダウンロードし、mysql コマンドを使用して復元する - `mysql -h <ホスト名> -P <ポート> -u <ユーザー名> -p src05 < src05_dump.sql` - 環境変数の設定 - 「.env.example」ファイルをコピーし、「.env」ファイルを作成する - - 環境変数を設定する。設定内容はPRJメンバーより共有を受けてください -- VSCodeの設定 + - 環境変数を設定する。設定内容は PRJ メンバーより共有を受けてください +- VSCode の設定 - 「.vscode/recommended_settings.json」ファイルをコピーし、「settings.json」ファイルを作成する - - 「python.defaultInterpreterPath」を、Pythonの構築手順で作成した仮想環境のパスに変更する + - 「python.defaultInterpreterPath」を、Python の構築手順で作成した仮想環境のパスに変更する ## 実行 -- VSCode上で「F5」キーを押下すると、バッチ処理が起動する。 +- VSCode 上で「F5」キーを押下すると、バッチ処理が起動する。 - 「entrypoint.py」が、バッチ処理のエントリーポイント。 - 実際の処理は、「src/jobctrl_daily.py」で行っている。 +## 単体テスト + +アルトマーク取込処理は、単体テストコードを使用してテスト自動化を行う + +### テスト準備 + +- VSCodeで以下の拡張機能をインストールする + - Python + - Python Test Explorer for Visual Studio Code + - Test Explorer UI +- VSCode 上でショートカット「ctrl」+「shift」+「P」でコマンドパレットを開く +- コマンドパレットの検索窓に「Python」と入力し、「Python: テストを構成する」を押下する +- 現在のワークスペースを選び、「pytest」を選択する +- 「tests」フォルダを選択する +- バックグランドで、pytest モジュールのインストールが始まれば成功 + +### テスト用のサブコマンド一覧 + +- `pipenv run`のあとに、サブコマンドとしてユーザー定義スクリプトを実行できる + - `Pipfile`内の「scripts」セクションに宣言する + +| コマンド | 概要 | +| ---------------- | -------------------------------------------------------------------------------------------- | +| test:ultmarc | tests/batch/ultmarc フォルダ配下のユニットテストを実行する | +| test:ultmarc:csv | tests/batch/ultmarc フォルダ配下のユニットテストを実行し、テストカバレッジを取得する(C1, C2) | + +### テスト共通関数の仕様 + +- tests/testing_utility.py内の共通関数の仕様について記載する + +#### create_ultmarc_test_data_from_csv + +- 引数 + - file_path: str +- 戻り値 + - src.batch.ultmarc.datfile.DatFileのインスタンス +- 処理概要 + - CSVファイルから、アルトマークのインプットデータを作成する + - データフォーマットは以下 + - 文字コード: UTF-8 + - 改行コード:LF + - ヘッダ: なし + - 値囲い: ダブルクォート + - アルトマークデータと文字コードを合わせるため、指定されたファイルを一時ディレクトリに、文字コード「cp932」で書き出してからテストデータとして読み込む + - テストデータそのものはUTF-8の文字コードで作成すること + +### create_db_data_from_csv + +- 引数 + - file_path: str +- 戻り値 + - テーブルのレコードに相当する辞書のリスト +- 処理概要 + - CSVファイルから、アルトマークテーブルに相当するテストデータを作成する + - テストの初期データ、期待値データを作成するのに利用する + - データフォーマットは以下 + - 文字コード: UTF-8 + - 改行コード:LF + - ヘッダ: なし + - 値囲い: ダブルクォート + - ファイル内の、以下の形式のデータを自動的に変換する + - `NULL` + - `None`に変換される + - `yyyy-mm-dd`もしくは、`yyyy/mm/dd`の文字 + - Date型に変換される + - `yyyy-mm-dd hh:mm:ss`もしくは、`yyyy/mm/dd hh:mm:ss`の文字 + - DateTime型に変換される + +### create_insert_sql_with_parameter + +- 引数 + - table_name: str テーブル名 + - column_names: list[str] カラム名のリスト + - test_data: list[str]: 値のリスト +- 戻り値 + - INSERT文とバインドパラメータ辞書 +- 処理概要 + - 引数を使用して、`src.db.Database#execute`メソッドで実行可能な形でINSERT文、バインドパラメータを作成する + +### create_delete_sql_with_parameter + +- 引数 + - table_name: str テーブル名 + - column_names: list[str] カラム名のリスト + - test_data: list[str]: 値のリスト +- 戻り値 + - DELETE文とバインドパラメータ辞書 +- 処理概要 + - 引数を使用して、`src.db.Database#execute`メソッドで実行可能な形でDELETE文、バインドパラメータを作成する + +### create_ultmarc_table_mapper_sut + +- 引数 + - line: src.batch.ultmarc.datfile.DatFileLine アルトマークデータファイルの1行 + - db: src.db.Database データベース操作クラス +- 戻り値 + - マッパークラス +- 処理概要 + - src.batch.ultmarc.utmp_tables.ultmarc_table_mapper_factory.UltmarcTableMapperFactoryを通じて、テスト対象のマッパークラスを生成して返す + +### assert_table_results + +- 引数 + - actual_rows: list[dict] テスト結果の辞書リスト + - expect_rows: list[dict] 期待値の辞書リスト + - ignore_col_name: list 比較を無視するDBのカラム名. Default None. +- 戻り値 + - なし +- 処理概要 + - テスト結果データと期待値データを突き合わせ、期待値どおりとなっているかを確認する + - ignore_col_nameに指定したカラムは、呼び出し元のテストコード内で個別に突き合わせする + ## フォルダ構成 ```text . -├── Pipfile -- Pythonモジュールの依存関係を管理するファイル -├── Dockerfile -- Dockerイメージを作成するためのファイル -├── Pipfile -- Pythonモジュールの依存関係を管理するファイル -├── Pipfile.lock -- Pythonモジュールの依存関係バージョン固定用ファイル -├── README.md -- 当ファイル -├── entrypoint.py -- バッチ処理のエントリーポイントになるpythonファイル -├── src -- ソースコードの保管場所 -│ ├── aws -- AWS関連処理 -│ │ └── s3.py -- S3クライアントとバケット処理 -│ ├── batch -- バッチ処理関連ソース置き場 -│ │ ├── batch_functions.py -- バッチ処理共通関数置き場 -│ │ ├── datachange -- 実績洗替関連ソース置き場 -│ │ │ └── emp_chg_inst_lau.py -- 施設担当者マスタ洗替 -│ │ └── jissekiaraigae.py -- 実績洗替処理のエントリーポイント -│ │ └── ultmarc -- アルトマーク関連処理 -│ │ ├── ultmarc_process.py -- アルトマーク関連処理のエントリーポイント -│ │ ├── datfile.py -- データファイル読込 -│ │ └── utmp_tables -- アルトマークテーブルへの登録関連 -│ │ ├── table_mapper -- テーブルへのデータマッピング処理 -│ │ │ ├── concrete -- テーブルマッパーのマッピング処理を行う具象クラス(全テーブル分) +├── Pipfile -- Pythonモジュールの依存関係を管理するファイル +├── Dockerfile -- Dockerイメージを作成するためのファイル +├── Pipfile -- Pythonモジュールの依存関係を管理するファイル +├── Pipfile.lock -- Pythonモジュールの依存関係バージョン固定用ファイル +├── README.md -- 当ファイル +├── entrypoint.py -- バッチ処理のエントリーポイントになるpythonファイル +├── src -- ソースコードの保管場所 +│ ├── aws -- AWS関連処理 +│ │ └── s3.py -- S3クライアントとバケット処理 +│ ├── batch -- バッチ処理関連ソース置き場 +│ │ ├── batch_functions.py -- バッチ処理共通関数置き場 +│ │ ├── datachange -- 実績洗替関連ソース置き場 +│ │ │ └── emp_chg_inst_lau.py -- 施設担当者マスタ洗替 +│ │ └── jissekiaraigae.py -- 実績洗替処理のエントリーポイント +│ │ └── ultmarc -- アルトマーク関連処理 +│ │ ├── ultmarc_process.py -- アルトマーク関連処理のエントリーポイント +│ │ ├── datfile.py -- データファイル読込 +│ │ └── utmp_tables -- アルトマークテーブルへの登録関連 +│ │ ├── table_mapper -- テーブルへのデータマッピング処理 +│ │ │ ├── concrete -- テーブルマッパーのマッピング処理を行う具象クラス(全テーブル分) │ │ │ │ ├── com_alma_mapper.py │ │ │ │ ├── ... -│ │ │ │ └── null_mapper.py -- テスト用、空振りするマッパークラス -│ │ │ └── ultmarc_table_mapper.py -- テーブルへの登録処理を行う抽象クラス -│ │ ├── tables -- アルトマークデータのDTOクラス(全テーブル分) +│ │ │ │ └── null_mapper.py -- テスト用、空振りするマッパークラス +│ │ │ └── ultmarc_table_mapper.py -- テーブルへの登録処理を行う抽象クラス +│ │ ├── tables -- アルトマークデータのDTOクラス(全テーブル分) │ │ │ ├── com_alma.py │ │ │ ├── ... -│ │ │ └── ultmarc_table.py -- アルトマークテーブルの抽象クラス -│ │ └── ultmarc_table_mapper_factory.py -- テーブルマッパー生成クラス +│ │ │ └── ultmarc_table.py -- アルトマークテーブルの抽象クラス +│ │ └── ultmarc_table_mapper_factory.py -- テーブルマッパー生成クラス │ ├── db -│ │ └── database.py -- データベース操作共通処理 +│ │ └── database.py -- データベース操作共通処理 │ ├── error -│ │ └── exceptions.py -- カスタム例外 -│ ├── jobctrl_daily.py -- 日次バッチ処理のエントリーポイント。「entrypoint.py」 から呼ばれる。 +│ │ └── exceptions.py -- カスタム例外 +│ ├── jobctrl_daily.py -- 日次バッチ処理のエントリーポイント。「entrypoint.py」 から呼ばれる。 │ ├── logging -│ │ └── get_logger.py -- ログ出力の共通処理 +│ │ └── get_logger.py -- ログ出力の共通処理 │ ├── system_var -│ │ └── environment.py -- 環境変数 +│ │ └── environment.py -- 環境変数 │ └── time -│ └── elapsed_time.py -- 実行時間計測用 +│ └── elapsed_time.py -- 実行時間計測用 +└── tests -- ユニットテストのルートディレクト + ├── batch + │ └── ultmarc -- アルトマーク関連のユニットテストを格納する + │ └── utmp_tables + │ └── table_mapper -- 以下、マッパークラス単位でフォルダを切る + │ └── com_alma + │ ├── test_com_alma_mapper.py -- テストコード本体 + │ ├── com_alma_insert.csv -- S3に配置される想定のテストCSVデータ。ケースごとに用意する。 + │ ... + │ ├── db_com_alma_before_update.csv -- テスト時に事前にDBに登録しておくデータ。CSVで用意する。 + │ ... + │ ├── expect_com_alma_insert.csv -- テストの期待値データ。CSVで用意する。 + │ ... + ├── conftest.py -- テスト内で共通利用できるフィクスチャを宣言する(執筆時点ではDBのみ) + └── testing_utility.py -- テストの共通関数 ``` diff --git a/ecs/jskult-batch-daily/tests/conftest.py b/ecs/jskult-batch-daily/tests/conftest.py index 0a6ce31c..a03a8638 100644 --- a/ecs/jskult-batch-daily/tests/conftest.py +++ b/ecs/jskult-batch-daily/tests/conftest.py @@ -1,7 +1,5 @@ """共通テストフィクスチャ""" -from datetime import datetime - import pytest from src.db.database import Database @@ -11,15 +9,3 @@ from src.db.database import Database def database() -> Database: """データベース接続モジュールを作成""" return Database.get_instance() - - -@pytest.fixture -def expect_datetime() -> datetime: - """テスト実行年月日時分秒を生成""" - return datetime.now().replace(microsecond=0) - - -@pytest.fixture -def expect_date_str(expect_datetime: datetime) -> str: - """テスト実行年月日の文字8桁を生成""" - return expect_datetime.strftime('%Y%m%d') diff --git a/ecs/jskult-batch-daily/tests/testing_utility.py b/ecs/jskult-batch-daily/tests/testing_utility.py index 3410d1f5..d11aa163 100644 --- a/ecs/jskult-batch-daily/tests/testing_utility.py +++ b/ecs/jskult-batch-daily/tests/testing_utility.py @@ -1,9 +1,7 @@ """テスト用共通処理関数""" import csv -import io import tempfile from datetime import datetime -from types import ModuleType from src.batch.ultmarc.datfile import DatFile, DatFileLine from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \ @@ -69,44 +67,6 @@ def create_db_data_from_csv(file_path: str) -> list[dict]: return rows -def create_ultmarc_test_csv(csv_rows: list[str]) -> DatFile: - """アルトマーク取込テストのCSVを作成 - Args: - csv_rows (tuple[str]): CSV文字列のリスト - Returns: - list[list[str]]: CSVデータ - """ - string_io = io.StringIO() - for csv_row in csv_rows: - string_io.write(csv_row) - string_io.write('\n') - string_io.seek(0) - dat_file = DatFile(string_io) - - return dat_file - - -def create_ultmarc_common_column_names() -> list[str]: - """アルトマークテーブル共通のカラム名を作成 - Returns: - list[str]: 共通カラム名 - """ - - return [ - 'regist_ymd', - 'update_ymd', - 'delete_ymd', - 'regist_date', - 'create_user', - 'update_date', - 'update_user', - 'sys_regist_date', - 'regist_prgm_id', - 'sys_update_date', - 'update_prgm_id' - ] - - def create_insert_sql_with_parameter(table_name: str, column_names: list[str], test_data: list[str]) -> tuple[str, dict]: """INSERT文と登録値のパラメータを返す @@ -144,41 +104,6 @@ def create_delete_sql_with_parameter(table_name: str, delete_parameter: dict[str return delete_sql, delete_parameter -def create_ultmarc_common_column_values(**kwargs) -> list: - """アルトマークテーブル共通のカラムを作成 - - Args: - kwargs 有効なキー一覧 - regist_ymd (str): 登録年月日 - update_ymd (str): 更新年月日 - delete_ymd (str): 削除年月日 - regist_date (datetime): 登録日時 - create_user (str): 登録者 - update_date (datetime): 更新日時 - update_user (str): 更新者 - sys_regist_date (datetime): システム登録日時 - regist_prgm_id (str): 登録プログラムid - sys_update_date (datetime): システム更新日時 - update_prgm_id (str): 更新プログラムid - Returns: - list: 共通カラム値 - """ - - return [ - kwargs.get('regist_ymd'), # 登録年月日(regist_ymd) - kwargs.get('update_ymd'), # 更新年月日(update_ymd) - kwargs.get('delete_ymd'), # 削除年月日(delete_ymd) - kwargs.get('regist_date'), # 登録日時(regist_date) - kwargs.get('create_user'), # 登録者(create_user) - kwargs.get('update_date'), # 更新日時(update_date) - kwargs.get('update_user'), # 更新者(update_user) - kwargs.get('sys_regist_date'), # システム登録日時(sys_regist_date) - kwargs.get('regist_prgm_id'), # 登録プログラムid(regist_prgm_id) - kwargs.get('sys_update_date'), # システム更新日時(sys_update_date) - kwargs.get('update_prgm_id') # 更新プログラムid(update_prgm_id) - ] - - def create_ultmarc_table_mapper_sut(line: DatFileLine, db: Database) -> UltmarcTableMapper: """アルトマークテーブルマッパーのインスタンスを返す @@ -202,18 +127,6 @@ def create_ultmarc_table_mapper_sut(line: DatFileLine, db: Database) -> UltmarcT return sut -def get_module_name(module: ModuleType) -> str: - """登録プログラムID、更新プログラムIDに登録するモジュール名を作成 - - Args: - module (ModuleType): pythonモジュール - - Returns: - str: モジュール名 - """ - return module.__name__.split('.')[-1] - - def is_valid_date_format(date_str: str, date_format): """日付文字列が、与えられたフォーマットにマッチするかを検査する @@ -237,6 +150,7 @@ def assert_table_results(actual_rows: list[dict], expect_rows: list[dict], ignor Args: actual_rows (list[dict]): テスト結果の辞書リスト expect_rows (list[dict]): 期待値の辞書リスト + ignore_col_name (list): 比較を無視するDBのカラム名. Default None. """ # 取得件数が一致すること assert len(actual_rows) == len(expect_rows)