投稿日
2010/12/1 水曜日
PythonでTDD(テスト駆動開発)する方法をググったら、標準のunittestの使い方とか、標準ではないけどnoseの使い方とかがたくさん出てきますが、どれもクラスや関数の使い方の説明に終始してて、実際の開発におけるテストケースを書いたソースファイルのディレクトリ構成や具体的なワークフローについて説明してる所はあまり無く。ググり方が悪いんですかね。
柔軟性が高いというかあまりディレクトリ構成やワークフローに影響を受けないから、各自好きにしろってことなのかな。
しかし、どんな方法にも対応出来るとはいっても、良い方法もあれば悪い方法もあるはず。
てことで自分的に良いと思われる方法・構成を考えてみた。
ただし気に入らない点があるので(後述)、後で解決方法を考える。
で、考えてみたのが以下のようなディレクトリ構成
もちろんディレクトリ名・ファイル名は適当(だけどいくつかの依存関係はある(後述))
ディレクトリの深さも特に制限はない
source
├── a.py
├── libs
│ ├── __init__.py
│ ├── b.py
│ ├── c.py
│ └── d.py
├── hoge
│ ├── __init__.py
│ ├── e.py
│ ├── f.py
│ ├── g.py
│ └── h.py
├── test.py
└── tests
├── __init__.py
├── atest.py
├── outputdata
│ └── i.txt
├── testdata
│ └── j.txt
├── tests_libs
│ ├── __init__.py
│ ├── btest.py
│ ├── ctest.py
│ ├── dtest.py
│ └── support.py
└── tests_hoge
├── __init__.py
├── etest.py
├── ftest.py
├── gtest.py
└── htest.py
#!/usr/bin/python # -*- coding: utf-8 -*- from unittest import TextTestRunner, TestCase import tests class AllTestCase(TestCase): def test_all(self): ttr = TextTestRunner(verbosity = 2) ttr.run(tests.get_all_test_suite()) if __name__ == "__main__": atc = AllTestCase() atc.test_all()
test.pyのポイント
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, glob
from unittest import TestSuite, TestLoader, TextTestRunner
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
def get_all_test_mods():
'''同階層のテストを全部インポートする'''
test_mods = []
pwd = os.getcwd()
os.chdir(CURRENT_DIR)
try:
for file in glob.glob('*test.py'):
test_mods.append(__import__(os.path.splitext(file.split('/')[-1])[0], globals(), locals(), []))
return test_mods
finally:
os.chdir(pwd)
def get_all_test_pkgs():
'''テストが定義されたパッケージをインポートする'''
test_pkgs = []
pwd = os.getcwd()
os.chdir(CURRENT_DIR)
try:
for file in glob.glob('*/__init__.py'):
pkg = __import__(file.split('/')[0], globals(), locals(), [])
if getattr(pkg, 'get_all_test_suite', None):
test_pkgs.append(pkg)
return test_pkgs
finally:
os.chdir(pwd)
def get_all_test_suite():
'''すべてのテストが含まれたTestSuiteを返す'''
all_tests = TestSuite()
for tm in get_all_test_mods():
suite = TestLoader().loadTestsFromModule(tm)
all_tests.addTest(suite)
for tp in get_all_test_pkgs():
suite = tp.get_all_test_suite()
all_tests.addTest(suite)
return all_tests
if __name__ == "__main__":
ttr = TextTestRunner(verbosity = 2)
ttr.run(get_all_test_suite())
__init__.pyのポイント
#!/usr/bin/python # -*- coding: utf-8 -*- from libs import b import unittest class BTestCase(unittest.TestCase): '''Bのテストケース''' def setUp(self): '''テスト前処理''' pass def tearDown(self): '''テスト終了処理''' pass def test1_hoge(self): '''hogeテスト''' # ここにテストコードを書く pass def test2_fuga(self): '''fugaテスト''' # ここにテストコードを書く pass if __name__ == '__main__': unittest.main()
tests_libs/btest.pyの例のポイント
ディレクトリ名・ファイル名は何でもいいのですが、今回の方法だと以下の依存関係があります。
気に入らない点
一応条件は満たしているものの微妙だ…
最近のコメント
たかたむ
はじめまして。初リアルフォース(R3ですが)で,同…
nokiyameego
ZFS poolのデバイスラベル破損で悩んていたと…
名前
しゅごい
Jane Doe
FYI Avoid Annoying Unexpe…
Jane Doe
ご存じとは思いますが、whileには、”~の間”と…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…