### ナビゲーション

- 索引
- モジュール |
- 次へ |
- 前へ |
- Python 2.6ja2 documentation »
- Python 標準ライブラリ »
- 25. 開発ツール »

# 25.5. `test` — Python用回帰テストパッケージ

ノート

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

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

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

参考

Module `unittest`
  PyUnit 回帰テストを書く。
Module `doctest`
  ドキュメンテーション文字列に埋め込まれたテスト。

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

`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 Driven Development
  コードより前にテストを書く方法論に関する Kent Beck の著書

## 25.5.2. `test.regrtest` を使ってテストを実行する

`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 を実行すると、すべての回帰テストを実行します。

## 25.5.3. `test.test_support` — テストのためのユーティリティ関数

ノート

`test.test_support` モジュールは、Python 3では `test.support` にリネームされました。

`test.test_support` モジュールでは、 Python の回帰テストに対するサポートを提供しています。

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

exception `test.test_support.``TestFailed`

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

exception `test.test_support.``TestSkipped`

  `TestFailed` のサブクラスです。テストがスキップされたとき送出されます。テスト時に (ネットワーク接続のような) 必要なリソースが利用できないときに送出されます。

exception `test.test_support.``ResourceDenied`

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

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

`test.test_support.``verbose`

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

`test.test_support.``have_unicode`

  ユニコードサポートが利用可能ならば `True` になります。

`test.test_support.``is_jython`

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

`test.test_support.``TESTFN`

  一時ファイルを作成するパスに設定されます。作成した一時ファイルは全て閉じ、 unlink (削除) せねばなりません。

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

`test.test_support.``forget`(module_name)

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

`test.test_support.``is_resource_enabled`(resource)

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

`test.test_support.``requires`(resource[, msg])

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

`test.test_support.``findfile`(filename)

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

`test.test_support.``run_unittest`(*classes)

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

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

      def test_main():
          test_support.run_unittest(__name__)

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

`test.test_support.``check_warnings`()

  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 で追加.

`test.test_support.``captured_stdout`()

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

  使用例:

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

  バージョン 2.6 で追加.

`test.test_support` モジュールは以下のクラスを定義しています。

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

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

  バージョン 2.6 で追加.

class `test.test_support.``EnvironmentVarGuard`

  一時的に環境変数をセット・アンセットするためのクラスです。このクラスのインスタンスはコンテキストマネージャーとして利用されます。

  バージョン 2.6 で追加.

`EnvironmentVarGuard.``set`(envvar, value)

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

`EnvironmentVarGuard.``unset`(envvar)

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

class `test.test_support.``WarningsRecorder`

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

  バージョン 2.6 で追加.

### ナビゲーション

- 索引
- モジュール |
- 次へ |
- 前へ |
- Python 2.6ja2 documentation »
- Python 標準ライブラリ »
- 25. 開発ツール »