25.5. "test" --- Python 用回帰テストパッケージ
**********************************************

注釈: "test" パッケージは、 Python の内部で使用されるためのものです
  。ドキ ュメントが書かれたのは Python のコア開発者の利便性を考えての
  ことです 。 Python の標準ライブラリ以外でこのパッケージを使用するこ
  とは、あま りお勧めできません。ここで触れられているコードは、Python
  のリリース の間に予告なく変更されたり削除されたりすることがあります
  。

"test" パッケージには、Python 用の全ての回帰テストの他に、
"test.support" モジュールと "test.regrtest" モジュールが入っています。
"test.support" はテストを充実させるために使い、 "test.regrtest" はテス
トスイートを実行するのに使います。

"test" パッケージ内のモジュールのうち、名前が "test_" で始まるものは、
特定のモジュールや機能に対するテストスイートです。新しいテストはすべて
"unittest" か "doctest" モジュールを使って書くようにしてください。古い
テストのいくつかは、 "sys.stdout" への出力を比較する「従来の」テスト形
式になっていますが、この形式のテストは廃止予定です。

参考:

  "unittest" モジュール
     PyUnit 回帰テストを書く。

  "doctest" モジュール
     ドキュメンテーション文字列に埋め込まれたテスト。


25.5.1. "test" パッケージのためのユニットテストを書く
=====================================================

"unittest" モジュールを使ってテストを書く場合、幾つかのガイドラインに
従うことが推奨されます。 1つは、テストモジュールの名前を、 "test_" で
始め、テスト対象となるモジュール名で終えることです。テストモジュール中
のテストメソッドは名前を "test_" で始めて、そのメソッドが何をテストし
ているかという説明で終えます。これはテスト実行プログラムが、そのメソッ
ドをテストメソッドとして認識するために必要です。また、テストメソッドに
はドキュメンテーション文字列を入れるべきではありません。コメント（例え
ば "# True あるいは False だけを返すテスト関数" ）を使用して、テストメ
ソッドのドキュメントを記述してください。これは、ドキュメンテーション文
字列が存在する場合はその内容が出力されてしまうため、どのテストを実行し
ているのかをいちいち表示したくないからです。

以下のような決まり文句を使います:

   import unittest
   from test import 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():
       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 Driven Development
     コードより前にテストを書く方法論に関する Kent Beck の著書。


25.5.2. コマンドラインインタフェースを利用してテストを実行する
==============================================================

"test.regrtest" はスクリプトとして Python の回帰テストスイートを実行で
きます。 "-m" オプションを利用して、 **python -m test.regrtest** とし
て実行します。スクリプトを実行すると、自動的に "test" パッケージ内のす
べての回帰テストを実行し始めます。パッケージ内の名前が "test_" で始ま
る全モジュールを見つけ、それをインポートし、もしあるなら関数
"test_main()" を実行してテストを行います。実行するテストの名前もスクリ
プトに渡される可能性があります。単一の回帰テストを指定 (**python -m
test.regrtest test_spam**) すると、出力を最小限にします。テストが成功
したかあるいは失敗したかだけを出力するので、出力は最小限になります。

直接 "test.regrtest" を実行すると、テストに利用するリソースを設定でき
ます。これを行うには、 "-u" コマンドラインオプションを使います。 "-u"
のオプションに "all" を指定すると、すべてのリソースを有効にします:
**python -m test.regrtest -uall** 。(よくある場合ですが) 何か一つを除
く全てが必要な場合、カンマで区切った不要なリソースのリストを "all" の
後に並べます。コマンド **python -m test.regrtest
-uall,-audio,-largefile** とすると、 "audio" と "largefile" リソースを
除く全てのリソースを使って "test.regrtest" を実行します。すべてのリソ
ースのリストと追加のコマンドラインオプションを出力するには、 **python
-m test.regrtest -h** を実行してください。

テストを実行しようとするプラットフォームによっては、回帰テストを実行す
る別の方法があります。 Unix では、Python をビルドしたトップレベルディ
レクトリで **make test** を実行できます。 Windows上では、 "PCBuild" デ
ィレクトリから **rt.bat** を実行すると、すべての回帰テストを実行します
。

バージョン 2.7.14 で変更: The "test" package can be run as a script:
**python -m test**. This works the same as running the "test.regrtest"
module.


25.6. "test.support" --- Utility functions for tests
****************************************************

注釈: The "test.test_support" module has been renamed to
  "test.support" in Python 3.x and 2.7.14.  The name
  "test.test_support" has been retained as an alias in 2.7.

The "test.support" module provides support for Python's regression
tests.

このモジュールは次の例外を定義しています:

exception test.support.TestFailed

   テストが失敗したとき送出される例外です。これは、 "unittest" ベース
   のテストでは廃止予定で、 "unittest.TestCase" の assertXXX メソッド
   が推奨されます。

exception test.support.ResourceDenied

   "unittest.SkipTest" のサブクラスです。 (ネットワーク接続のような)
   リソースが利用できないとき送出されます。 "requires()" 関数によって
   送出されます。

"test.support" モジュールでは、以下の定数を定義しています:

test.support.verbose

   冗長な出力が有効な場合は "True" です。実行中のテストについてのより
   詳細な情報が欲しいときにチェックします。 *verbose* は
   "test.regrtest" によって設定されます。

test.support.have_unicode

   Unicode サポートが利用可能ならば "True" になります。

test.support.is_jython

   実行中のインタプリタが Jython ならば "True" になります。

test.support.TESTFN

   テンポラリファイルの名前として安全に利用できる名前に設定されます。
   作成した一時ファイルは全て閉じ、unlink (削除) しなければなりません
   。

test.support.TEST_HTTP_URL

   Define the URL of a dedicated HTTP server for the network tests.

"test.support" モジュールでは、以下の関数を定義しています:

test.support.forget(module_name)

   モジュール名 *module_name* を "sys.modules" から取り除き、モジュー
   ルのバイトコンパイル済みファイルを全て削除します。

test.support.is_resource_enabled(resource)

   *resource* が有効で利用可能ならば "True" を返します。利用可能なリソ
   ースのリストは、 "test.regrtest" がテストを実行している間のみ設定さ
   れます。

test.support.requires(resource[, msg])

   *resource* が利用できなければ、 "ResourceDenied" を送出します。その
   場合、 *msg* は "ResourceDenied" の引数になります。 "__name__" が
   ""__main__"" である関数にから呼び出された場合には常に "True" を返し
   ます。テストを "test.regrtest" から実行するときに使われます。

test.support.findfile(filename)

   *filename* という名前のファイルへのパスを返します。一致するものが見
   つからなければ、 *filename* 自体を返します。 *filename* 自体もファ
   イルへのパスでありえるので、 *filename* が返っても失敗ではありませ
   ん。

test.support.run_unittest(*classes)

   渡された "unittest.TestCase" サブクラスを実行します。この関数は名前
   が "test_" で始まるメソッドを探して、テストを個別に実行します。

   引数に文字列を渡すことも許可されています。その場合、文字列は
   "sys.module" のキーでなければなりません。指定された各モジュールは、
   "unittest.TestLoader.loadTestsFromModule()" でスキャンされます。こ
   の関数は、よく次のような "test_main()" 関数の形で利用されます。

      def test_main():
          support.run_unittest(__name__)

   この関数は、名前で指定されたモジュールの中の全ての定義されたテスト
   を実行します。

test.support.check_warnings(*filters, quiet=True)

   warning が正しく発行されているかどうかチェックする、
   "warnings.catch_warnings()" を使いやすくするラッパーです。これは、
   "warnings.simplefilter()" を "always" に設定して、記録された結果を
   自動的に検証するオプションと共に
   "warnings.catch_warnings(record=True)" を呼ぶのとほぼ同じです。

   "check_warnings" は "("message regexp", WarningCategory)" の形をし
   た 2要素タプルをポジション引数として受け取ります。1つ以上の
   *filters* が与えられた場合や、オプションのキーワード引数 *quiet* が
   "False" の場合、警告が期待通りであるかどうかをチェックします。指定
   された各 filter は最低でも1回は囲われたコード内で発生した警告とマッ
   チしなければテストが失敗しますし、指定されたどの filter ともマッチ
   しない警告が発生してもテストが失敗します。前者のチェックを無効にす
   るには、 *quiet* を "True" にします。

   引数が1つもない場合、デフォルトでは次のようになります:

      check_warnings(("", Warning), quiet=True)

   この場合、全ての警告は補足され、エラーは発生しません。

   コンテキストマネージャーに入る時、 "WarningRecorder" インスタンスが
   返されます。このレコーダーオブジェクトの "warnings" 属性から、
   "catch_warnings()" から得られる警告のリストを取得することができます
   。便利さのために、レコーダーオブジェクトから直接、一番最近に発生し
   た警告を表すオブジェクトの属性にアクセスできます(以下にある例を参照
   してください)。警告が1つも発生しなかった場合、それらの全ての属性は
   "None" を返します。

   レコーダーオブジェクトの "reset()" メソッドは警告リストをクリアしま
   す。

   コンテキストマネージャーは次のようにして使います:

      with check_warnings(("assertion is always true", SyntaxWarning),
                          ("", UserWarning)):
          exec('assert(False, "Hey!")')
          warnings.warn(UserWarning("Hide me!"))

   この場合、どちらの警告も発生しなかった場合や、それ以外の警告が発生
   した場合は、 "check_warnings()" はエラーを発生させます。

   警告が発生したかどうかだけでなく、もっと詳しいチェックが必要な場合
   は、次のようなコードになります:

      with check_warnings(quiet=True) as w:
          warnings.warn("foo")
          assert str(w.args[0]) == "foo"
          warnings.warn("bar")
          assert str(w.args[0]) == "bar"
          assert str(w.warnings[0].args[0]) == "foo"
          assert str(w.warnings[1].args[0]) == "bar"
          w.reset()
          assert len(w.warnings) == 0

   全ての警告をキャプチャし、テストコードがその警告を直接テストします
   。

   バージョン 2.6 で追加.

   バージョン 2.7 で変更: 新しいオプション引数 *filters* と *quiet*

test.support.check_py3k_warnings(*filters, quiet=False)

   "check_warnings()" と似ていますが、 Python 3 互換性警告のためのもの
   です。 "sys.py3kwarning == 1" の時、警告が実際に発生していることを
   チェックします。 "sys.py3kwarning == 0" の時、警告が発生していない
   ことをチェックします。ポジション引数として "("message regexp",
   WarningCategory)" の形をした 2要素タプルを受け取ります。オプション
   引数 *quiet* が "True" のとき、filter になにもマッチしなくても失敗
   しません。引数がない場合は次と同じになります:

      check_py3k_warnings(("", DeprecationWarning), quiet=False)

   バージョン 2.7 で追加.

test.support.captured_stdout()

   これは、 "with" 文の body で "sys.stdout" として
   "StringIO.StringIO" オブジェクトを利用するコンテキストマネージャー
   です。このオブジェクトは、 "with" 文の "as" 節で受け取ることができ
   ます。

   使用例:

      with captured_stdout() as s:
          print "hello"
      assert s.getvalue() == "hello\n"

   バージョン 2.6 で追加.

test.support.import_module(name, deprecated=False)

   この関数は *name* で指定されたモジュールを import して返します。通
   常の import と異なり、この関数はモジュールを import できなかった場
   合に "unittest.SkipTest" 例外を発生させます。

   *deprecated* が "True" の場合、 import 中はモジュールとパッケージの
   廃止メッセージが抑制されます。

   バージョン 2.7 で追加.

test.support.import_fresh_module(name, fresh=(), blocked=(), deprecated=False)

   この関数は、 *name* で指定された Python モジュールを、 import 前に
   "sys.modules" から削除することで新規に import してそのコピーを返し
   ます。 "reload()" 関数と違い、もとのモジュールはこの操作によって影
   響をうけません。

   *fresh* は、同じように import 前に "sys.modules" から削除されるモジ
   ュール名の iterable です。

   *blocked* もモジュール名の iterable で、 import 中にモジュールキャ
   ッシュ内でその名前を "0" に置き換えることで、そのモジュールを
   import しようとすると "ImportError" を発生させます。

   指定されたモジュールと *fresh* や *blocked* 引数内のモジュール名は
   import 前に保存され、 fresh import が完了したら "sys.modules" に戻
   されます。

   *deprecated* が "True" の場合、 import 中はモジュールとパッケージの
   廃止メッセージが抑制されます。

   この関数はモジュールを import できなかった場合に
   "unittest.SkipTest" 例外を送出します。

   使用例:

      # Get copies of the warnings module for testing without
      # affecting the version being used by the rest of the test suite
      # One copy uses the C implementation, the other is forced to use
      # the pure Python fallback implementation
      py_warnings = import_fresh_module('warnings', blocked=['_warnings'])
      c_warnings = import_fresh_module('warnings', fresh=['_warnings'])

   バージョン 2.7 で追加.

"test.support" モジュールでは、以下のクラスを定義しています:

class test.support.TransientResource(exc[, **kwargs])

   このクラスのインスタンスはコンテキストマネージャーで、指定された型
   の例外が発生した場合に "ResourceDenied" 例外を発生させます。キーワ
   ード引数は全て、 "with" 文の中で発生した全ての例外の属性名/属性値と
   比較されます。全てのキーワード引数が例外の属性に一致した場合に、
   "ResourceDenied" 例外が発生します。

   バージョン 2.6 で追加.

class test.support.EnvironmentVarGuard

   一時的に環境変数をセット・アンセットするためのクラスです。このクラ
   スのインスタンスはコンテキストマネージャーとして利用されます。また
   、 "os.environ" に対する参照・更新を行う完全な辞書のインタフェース
   を持ちます。コンテキストマネージャーが終了した時、このインスタンス
   経由で環境変数へ行った全ての変更はロールバックされます。

   バージョン 2.6 で追加.

   バージョン 2.7 で変更: 辞書のインタフェースを追加しました。

EnvironmentVarGuard.set(envvar, value)

   一時的に、 "envvar" を "value" にセットします。

EnvironmentVarGuard.unset(envvar)

   一時的に "envvar" をアンセットします。

class test.support.WarningsRecorder

   ユニットテスト時に warning を記録するためのクラスです。上の、
   "check_warnings()" のドキュメントを参照してください。

   バージョン 2.6 で追加.
