投稿日
          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://…