はじめに
Pythonで色々コードを書いているときに
- どこに何の処理が書いてあるのかわかりづらい
- 処理/機能毎にフォルダ分けしておきたい
と思ったので、個人的なメモを残しておく。
フォルダ構成の必要性
- 可読性・保守性の向上
- コードの構造を視覚的に表現することで、目的の処理がどこに配置されているか分かりやすく、デバッグやメンテナンスが容易となる
- 管理効率化
- 階層構造を明確にすることでファイルを探す手間が省け、プロジェクト全体を効率的に管理できる
- 規模が大きくなっても耐えられる
- 目的別にフォルダ構成が分けられていると、機能追加等による拡張がしやすくなる
Pythonフォルダ構成(例)
● 構成
[ project ]
├ [ project ] # ソースコードを保管するフォルダ
│ ├ [ config ]
│ │ └ settings.py # 設定ファイル
│ ├ [ package1 ]
│ │ ├ __init__.py ※
│ │ └ moduleA.py
│ ├ [ package2 ]
│ │ ├ __init__.py ※
│ │ └ moduleB.py
│ ├ __main__.py
│ └ main.py
├ [ tests ] # テストのためのコードを保管するフォルダ
│ └ test.py
├ [ doc ] # プロジェクトにおけるドキュメントを保管するフォルダ
└ Readme.md
※昔はパッケージには必ず init.py が必要だったけど、最近(Python 3.3以降)は必須でなくなりました。ただ、互換性を考えて今でも置いておくのが一般的です。
メイン処理
main.py
from .package1 import moduleA
from .package2 import moduleB
def main():
moduleA.func("kinouA")
moduleB.func("kinouB")
if __name__ == '__main__':
main()
__main__.py
if __name__ == '__main__':
from .main import main
main()
各パッケージ(サブモジュール)
moduleA.py
def func(msg):
print("A:",msg)
return
if __name__ == '__main__':
func()
moduleB.py
def func(msg):
print("B:",msg)
return
if __name__ == '__main__':
func()
● 実行
project $ python -m prj
A: kinouA
B: kinouB
● テスト
test.py
import unittest
from unittest.mock import patch
from prj.package1 import moduleA
class TestUser(unittest.TestCase):
@patch('builtins.print')
def test_func_prints_message(self, mock_print):
moduleA.func("kinouA")
mock_print.assert_called_once_with("A:", "kinouA")
if __name__ == "__main__":
unittest.main()
project $ python -m unittest discover test
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
補足
標準出力と戻り値の両方をテストする場合
moduleA.py
def func(msg):
print("A:",msg)
return True
test.py
class TestFunc(unittest.TestCase):
@patch('builtins.print')
def test_func_prints_message_and_returns_true(self, mock_print):
# Act
result = moduleA.func("Hello")
# Assert: printの呼び出しをチェック
mock_print.assert_called_once_with("A:", "Hello")
# Assert: 戻り値をチェック
self.assertTrue(result)
テスト関数の名前付け、基本ルール
- 必ず test_ から始める(unittestが自動で見つけるため)
- 何をテストしているかが人間に読んでわかるようにする
- 動作+条件+期待結果 をなるべく含めると良い
参考