ノート
test パッケージは、 Python の内部で使用されるためのものです。ドキュメントが書かれたのは Python のコア開発者の利便性を考えてのことです。 Python の標準ライブラリ以外でこのパッケージを使用することは、あまりお勧めできません。ここで触れられているコードは、Python のリリースの間に予告なく変更されたり削除されたりすることがあります。
test パッケージには、Python 用の全ての回帰テストの他に、 test.test_support モジュールと test.regrtest モジュールが入っています。 test.test_support はテストを充実させるために使い、 test.regrtest はテストスイートを実行するのに使います。
test パッケージ内のモジュールのうち、名前が test_ で始まるものは、特定のモジュールや機能に対するテストスイートです。新しいテストはすべて unittest か doctest モジュールを使って書くようにしてください。古いテストのいくつかは、 sys.stdout への出力を比較する「従来の」テスト形式になっていますが、この形式のテストは廃止予定です。
unittest モジュールを使ってテストを書く場合、幾つかのガイドラインに従うことが推奨されます。 1つは、テストモジュールの名前を、 test_ で始め、テスト対象となるモジュール名で終えることです。テストモジュール中のテストメソッドは名前を test_ で始めて、そのメソッドが何をテストしているかという説明で終えます。これはテスト実行プログラムが、そのメソッドをテストメソッドとして認識するために必要です。また、テストメソッドにはドキュメンテーション文字列を入れるべきではありません。コメント(例えば # True あるいは False だけを返すテスト関数 )を使用して、テストメソッドのドキュメントを記述してください。これは、ドキュメンテーション文字列が存在する場合はその内容が出力されてしまうため、どのテストを実行しているのかをいちいち表示したくないからです。
以下のような決まり文句を使います:
import unittest
from test import test_support
class MyTestCase1(unittest.TestCase):
# Only use setUp() and tearDown() if necessary
def setUp(self):
... code to execute in preparation for tests ...
def tearDown(self):
... code to execute to clean up after tests ...
def test_feature_one(self):
# Test feature one.
... testing code ...
def test_feature_two(self):
# Test feature two.
... testing code ...
... more test methods ...
class MyTestCase2(unittest.TestCase):
... same structure as MyTestCase1 ...
... more test classes ...
def test_main():
test_support.run_unittest(MyTestCase1,
MyTestCase2,
... list other tests ...
)
if __name__ == '__main__':
test_main()
この定型的なコードによって、テストスイートを regrtest.py から起動できると同時に、スクリプト自体からも実行できるようになります。
回帰テストの目的はコードを解き明かすことです。そのためには以下のいくつかのガイドラインに従ってください:
テストスイートから、すべてのクラス、関数および定数を実行するべきです。これには外部に公開される外部APIだけでなく「プライベートな」コードも含みます。
ホワイトボックス・テスト(対象のコードの詳細を元にテストを書くこと)を推奨します。ブラックボックス・テスト(公開されるインタフェース仕様だけをテストすること)は、すべての境界条件を確実にテストするには完全ではありません。
すべての取りうる値を、無効値も含めてテストするようにしてください。そのようなテストを書くことで、全ての有効値が通るだけでなく、不適切な値が正しく処理されることも確認できます。
コード内のできる限り多くのパスを網羅してください。分岐するように入力を調整したテストを書くことで、コードの多くのパスをたどることができます。
テスト対象のコードにバグが発見された場合は、明示的にテスト追加するようにしてください。そのようなテストを追加することで、将来コードを変更した際にエラーが再発することを防止できます。
テストの後始末(例えば一時ファイルをすべて閉じたり削除したりすること)を必ず行ってください。
テストがオペレーティングシステムの特定の状況に依存する場合、テスト開始時に条件を満たしているかを検証してください。
import するモジュールをできるかぎり少なくし、可能な限り早期に import を行ってください。そうすることで、てテストの外部依存性を最小限にし、モジュールの import による副作用から生じる変則的な動作を最小限にできます。
できる限りテストコードを再利用するようにしましょう。時として、入力の違いだけを記述すれば良くなるくらい、テストコードを小さくすることができます。例えば以下のように、サブクラスで入力を指定することで、コードの重複を最小化することができます:
class TestFuncAcceptsSequences(unittest.TestCase):
func = mySuperWhammyFunction
def test_func(self):
self.func(self.arg)
class AcceptLists(TestFuncAcceptsSequences):
arg = [1,2,3]
class AcceptStrings(TestFuncAcceptsSequences):
arg = 'abc'
class AcceptTuples(TestFuncAcceptsSequences):
arg = (1,2,3)
参考
test.regrtest を使うと Python の回帰テストスイートを実行できます。スクリプトを単独で実行すると、自動的に test パッケージ内のすべての回帰テストを実行し始めます。パッケージ内の名前が test_ で始まる全モジュールを見つけ、それをインポートし、もしあるなら関数 test_main() を実行してテストを行います。実行するテストの名前もスクリプトに渡される可能性があります。単一の回帰テストを指定 (python regrtest.py test_spam.py) すると、出力を最小限にします。テストが成功したかあるいは失敗したかだけを出力するので、出力は最小限になります。
直接 test.regrtest を実行すると、テストに利用するリソースを設定できます。これを行うには、 -u コマンドラインオプションを使います。すべてのリソースを使うには、 python regrtest.py -uall を実行します。 -u のオプションに all を指定すると、すべてのリソースを有効にします。(よくある場合ですが) 何か一つを除く全てが必要な場合、カンマで区切った不要なリソースのリストを all の後に並べます。コマンド python regrtest.py -uall,-audio,-largefile とすると、 audio と largefile リソースを除く全てのリソースを使って test.regrtest を実行します。すべてのリソースのリストと追加のコマンドラインオプションを出力するには、 python regrtest.py -h を実行してください。
テストを実行しようとするプラットフォームによっては、回帰テストを実行する別の方法があります。 Unix では、Python をビルドしたトップレベルディレクトリで make test を実行できます。 Windows上では、 PCBuild ディレクトリから rt.bat を実行すると、すべての回帰テストを実行します。
ノート
test.test_support モジュールは、Python 3では test.support にリネームされました。
test.test_support モジュールでは、 Python の回帰テストに対するサポートを提供しています。
このモジュールは次の例外を定義しています:
テストが失敗したとき送出される例外です。これは、 unittest ベースのテストでは廃止予定で、 unittest.TestCase の assertXXX メソッドが推奨されます。
TestFailed のサブクラスです。テストがスキップされたとき送出されます。テスト時に (ネットワーク接続のような) 必要なリソースが利用できないときに送出されます。
TestSkipped のサブクラスです。(ネットワーク接続のような)リソースが利用できないとき送出されます。 requires() 関数によって送出されます。
test.test_support モジュールでは、以下の定数を定義しています:
冗長な出力が有効な場合は True です。実行中のテストについてのより詳細な情報が欲しいときにチェックします。 verbose は test.regrtest によって設定されます。
一時ファイルを作成するパスに設定されます。作成した一時ファイルは全て閉じ、 unlink (削除) せねばなりません。
test.test_support モジュールでは、以下の関数を定義しています:
モジュール名 module_name を sys.modules から取り除き、モジュールのバイトコンパイル済みファイルを全て削除します。
resource が有効で利用可能ならば True を返します。利用可能なリソースのリストは、 test.regrtest がテストを実行している間のみ設定されます。
resource が利用できなければ、 ResourceDenied を送出します。その場合、 msg は ResourceDenied の引数になります。 __name__ が "__main__" である関数にから呼び出された場合には常に真を返します。テストを test.regrtest から実行するときに使われます。
filename という名前のファイルへのパスを返します。一致するものが見つからなければ、 filename 自体を返します。 filename 自体もファイルへのパスでありえるので、 filename が返っても失敗ではありません。
渡された unittest.TestCase サブクラスを実行します。この関数は名前が test_ で始まるメソッドを探して、テストを個別に実行します。
引数に文字列を渡すことも許可されています。その場合、文字列は sys.module のキーでなければなりません。指定された各モジュールは、 unittest.TestLoader.loadTestsFromModule() でスキャンされます。この関数は、よく次のような test_main() 関数の形で利用されます。
def test_main():
test_support.run_unittest(__name__)
この関数は、名前で指定されたモジュールの中の全ての定義されたテストを実行します。
warning が正しく発行されているかどうか1つのassertionでチェックする、 warnings.catch_warnings() を使いやすくするラッパーです。これは、 warnings.catch_warnings(record=True) を呼ぶのとほぼ同じです。
主な違いは、この関数がコンテキストマネージャーのエントリーになっていることです。ただのリストの代わりに、 WarningRecorder のインスタンスが返されます。 warning のリストには、 recorder オブジェクトの warnings 属性からアクセスできます。また、最後に発生した warning には、オブジェクトから直接アクセスすることができます。 warning が1つも発生しなかった場合は、後者の属性は None になります。
recorder オブジェクトは reset() メソッドを持っています。このメソッドは warning リストをクリアします。
コンテキストマネージャーは次のようにして利用します。
with check_warnings() as w:
warnings.simplefilter("always")
warnings.warn("foo")
assert str(w.message) == "foo"
warnings.warn("bar")
assert str(w.message) == "bar"
assert str(w.warnings[0].message) == "foo"
assert str(w.warnings[1].message) == "bar"
w.reset()
assert len(w.warnings) == 0
バージョン 2.6 で追加.
これは、 with 文の body で sys.stdout として StringIO.StringIO オブジェクトを利用するコンテキストマネージャーです。このオブジェクトは、 with 文の as 節で受け取ることができます。
使用例:
with captured_stdout() as s:
print "hello"
assert s.getvalue() == "hello"
バージョン 2.6 で追加.
test.test_support モジュールは以下のクラスを定義しています。
このクラスのインスタンスはコンテキストマネージャーで、指定された型の例外が発生した場合に ResourceDenied 例外を発生させます。キーワード引数は全て、 with 文の中で発生した全ての例外の属性名/属性値と比較されます。全てのキーワード引数が例外の属性に一致した場合に、 ResourceDenied 例外が発生します。
バージョン 2.6 で追加.
一時的に環境変数をセット・アンセットするためのクラスです。このクラスのインスタンスはコンテキストマネージャーとして利用されます。
バージョン 2.6 で追加.
一時的に、 envvar を value にセットします。
一時的に envvar をアンセットします。
ユニットテスト時にwarningを記録するためのクラスです。上の、 check_warnings() のドキュメントを参照してください。
バージョン 2.6 で追加.