Pythonテストフレームワーク nose2 徹底解説ガイド

はじめに: nose2とは?

nose2 は、Pythonの標準ライブラリである unittest を拡張し、より便利で高機能なテスト実行環境を提供することを目的としたテストフレームワークです。オリジナルの nose フレームワークの後継として開発されました。

unittest に慣れ親しんでいる開発者にとって、nose2 はスムーズに導入できる選択肢となります。unittest の基本的な機能やテストケースの書き方を踏襲しつつ、プラグインシステムによる豊富な機能拡張、柔軟なテストディスカバリ(テストの自動検出)、設定ファイルによるカスタマイズ性などを提供します。

主な特徴をまとめると以下のようになります。

  • unittest の拡張: unittest をベースにしており、既存の unittest テストコードとの互換性があります。
  • 強力なプラグインシステム: カバレッジ計測、テスト結果レポート、並列実行、ロギングなど、様々な機能をプラグインとして追加できます。
  • 柔軟なテストディスカバリ: ファイル名やクラス名、関数名の規約に基づいてテストを自動的に検出します。
  • 設定ファイル: unittest.cfg または nose2.cfg というINI形式の設定ファイルで、テストの実行方法やプラグインの挙動を細かく制御できます。
  • パラメータ化テスト: @params デコレータを使って、一つのテストメソッドに複数のパラメータセットを与えて実行できます。

ただし、現在のPythonテストエコシステムにおいては、pytest が非常に人気があり、より活発なコミュニティと多くの機能を持っています。nose2 の公式ドキュメントでも、新しいプロジェクトには pytest を検討することを推奨しています。それでも、unittest ベースのプロジェクトや、nose からの移行パスとして nose2 を理解しておく価値はあります。

インストールと基本的な使い方

インストール

nose2 はpipを使って簡単にインストールできます。

pip install nose2

特定のプラグイン(例えばカバレッジ)を一緒にインストールすることも可能です。

pip install nose2[coverage_plugin]

基本的なテストの書き方と実行

nose2unittest をベースにしているため、unittest と同様のスタイルでテストを記述できます。

例えば、以下のような簡単な関数があるとします。

# mymath.py
def add(a, b):
    return a + b

def multiply(a, b):
    return a * b

これに対するテストを unittest.TestCase を使って書きます。ファイル名は test で始まるようにします(例: test_mymath.py)。

# test_mymath.py
import unittest
from mymath import add, multiply

class MyMathTest(unittest.TestCase):

    def test_add(self):
        self.assertEqual(add(2, 3), 5)
        self.assertEqual(add(-1, 1), 0)
        self.assertEqual(add(0, 0), 0)

    def test_multiply(self):
        self.assertEqual(multiply(2, 3), 6)
        self.assertEqual(multiply(-1, 5), -5)
        self.assertEqual(multiply(0, 100), 0)

if __name__ == '__main__':
    # unittest.main() でも実行できるが、nose2コマンドを使うのが一般的
    import nose2
    nose2.main()

テストを実行するには、プロジェクトのルートディレクトリなどで nose2 コマンドを実行します。

nose2

詳細な情報を表示したい場合は -v (verbose) オプションを付けます。

nose2 -v

実行結果の例:

test_add (test_mymath.MyMathTest) ... ok
test_multiply (test_mymath.MyMathTest) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

nose2 は、デフォルトでカレントディレクトリ以下を探索し、test で始まるPythonファイル(test*.py)を見つけ、その中の unittest.TestCase サブクラスや test で始まる関数を実行します。

テストの発見 (Test Discovery)

nose2 の強力な機能の一つが、テストの自動検出(Test Discovery)です。特別な設定なしに、規約に従って書かれたテストコードを見つけ出してくれます。

デフォルトの検出ルールは以下の通りです。

  • ディレクトリ: カレントディレクトリから探索を開始します。__init__.py が存在するパッケージディレクトリや、名前に test を含むディレクトリ、libsrc という名前のディレクトリも探索対象になります。
  • ファイル名: 名前の先頭が test で始まるPythonファイル (test*.py) をテストモジュールとして認識します。このパターンは設定ファイルで変更可能です。
  • クラス名: テストモジュール内で、unittest.TestCase を継承し、かつクラス名の先頭が Test で始まるクラスをテストクラスとして認識します。
  • メソッド/関数名: テストクラス内で、名前の先頭が test で始まるメソッドをテストメソッドとして認識します。また、テストモジュール内で、クラスに属さず、名前の先頭が test で始まる関数もテスト関数として認識されます。

これらのルールは、nose2 に組み込まれているテストローダープラグインによって実装されています。もし、プロジェクトの構造や命名規則がこれらのデフォルトルールに合わない場合は、設定ファイルやカスタムプラグインで挙動を変更することができます。

Tips: プロジェクトのルートに __init__.py を置くと、nose2 がテストを発見しやすくなることがあります。特に、テストファイルがサブディレクトリにある場合に有効です。

設定ファイル (`unittest.cfg` / `nose2.cfg`)

nose2 の動作は、プロジェクトのルートディレクトリに置かれた設定ファイルで細かくカスタマイズできます。ファイル名は unittest.cfg または nose2.cfg がデフォルトで認識されます。INI形式で記述します。

設定ファイルは主に [unittest] セクションと、各プラグインに対応するセクション(例: [coverage], [multiprocess])で構成されます。

[unittest] セクションの主な設定項目

設定項目 説明 デフォルト値
start-dir テスト探索を開始するディレクトリ。 . (カレントディレクトリ) tests
code-directories テスト対象のコードが含まれるディレクトリ。sys.path と探索パスに追加されます。複数指定する場合は改行して記述します。 なし (lib, src は暗黙的に追加される場合がある) src
my_lib
test-file-pattern テストモジュールとして認識するファイル名のパターン (glob形式)。 test*.py *_test.py
test-method-prefix テストメソッド/関数として認識する名前の接頭辞。 test check_
plugins 追加でロードするプラグインのモジュール名をリスト形式で指定します(改行区切り)。 なし nose2.plugins.layers
my_custom_plugin
exclude-plugins 自動ロードされるプラグインから除外するプラグインのモジュール名をリスト形式で指定します。 なし nose2.plugins.loader.functions

設定ファイルの例

以下は、テスト探索の開始ディレクトリを tests に、テストファイルのパターンを *_test.py に変更し、カバレッジプラグインとレイヤープラグインを有効にする設定例です。

[unittest]
start-dir = tests
test-file-pattern = *_test.py
code-directories =
  src
plugins =
  nose2.plugins.coverage
  nose2.plugins.layers

[coverage]
always-on = True
coverage-report =
  term-missing
  html
coverage-config = .coveragerc

[layers]
always-on = True

設定ファイルを活用することで、コマンドラインオプションを毎回指定する手間を省き、プロジェクト全体で一貫したテスト実行環境を構築できます。

注意: nose2 は設定ファイルとして pyproject.toml 内の [tool.nose2] テーブルもサポートしています (バージョン 0.15.0 以降)。TOML形式での設定も可能です。

フィクスチャ (Fixtures)

テストを実行する際には、テストの前処理(セットアップ)や後処理(ティアダウン)が必要になることがよくあります。例えば、テスト用のデータベース接続を確立したり、一時ファイルを作成したり、テスト後にそれらをクリーンアップしたりする場合です。nose2unittest のフィクスチャ機能をそのまま利用できます。

unittest.TestCase で利用可能な主なフィクスチャメソッドは以下の通りです。

メソッド 実行タイミング 説明
setUp() 各テストメソッドの実行 個々のテストメソッドに必要な前処理を記述します。
tearDown() 各テストメソッドの実行 個々のテストメソッドの後処理(クリーンアップ)を記述します。テストメソッドが成功したか失敗したかに関わらず実行されます。
setUpClass(cls) テストクラス内の最初のテストメソッド実行に1回だけ クラス全体で共有する比較的高コストなセットアップ処理(例: データベース接続、Webサーバー起動)を記述します。クラスメソッド (@classmethod) として定義する必要があります。
tearDownClass(cls) テストクラス内の全てのテストメソッド実行に1回だけ setUpClass でセットアップしたリソースのクリーンアップを行います。クラスメソッド (@classmethod) として定義する必要があります。
setUpModule() モジュール内の最初のテスト実行に1回だけ モジュールレベルでのセットアップ処理を記述します。関数として定義します。
tearDownModule() モジュール内の全てのテスト実行に1回だけ setUpModule でセットアップしたリソースのクリーンアップを行います。関数として定義します。

フィクスチャの使用例

# test_fixture_example.py
import unittest
import tempfile
import os

# モジュールレベルのフィクスチャ
module_setup_done = False
module_temp_dir = None

def setUpModule():
    global module_setup_done, module_temp_dir
    print("\n[Module Setup]")
    module_temp_dir = tempfile.TemporaryDirectory()
    print(f" Created temporary directory: {module_temp_dir.name}")
    module_setup_done = True

def tearDownModule():
    print("\n[Module Teardown]")
    if module_temp_dir:
        print(f" Cleaning up temporary directory: {module_temp_dir.name}")
        module_temp_dir.cleanup()

class FixtureTest(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print("\n [Class Setup]")
        cls.class_resource = "Class Resource Created"
        print(f"  {cls.class_resource}")

    @classmethod
    def tearDownClass(cls):
        print("\n [Class Teardown]")
        print(f"  Cleaning up: {cls.class_resource}")
        del cls.class_resource

    def setUp(self):
        print("  [Method Setup]")
        self.temp_file = tempfile.NamedTemporaryFile(dir=module_temp_dir.name, delete=False)
        print(f"   Created temp file: {self.temp_file.name}")
        self.temp_file.write(b"test data")
        self.temp_file.close()

    def tearDown(self):
        print("  [Method Teardown]")
        print(f"   Removing temp file: {self.temp_file.name}")
        os.remove(self.temp_file.name)

    def test_method_1(self):
        print("   Running test_method_1")
        self.assertTrue(module_setup_done)
        self.assertEqual(self.class_resource, "Class Resource Created")
        with open(self.temp_file.name, 'rb') as f:
            self.assertEqual(f.read(), b"test data")

    def test_method_2(self):
        print("   Running test_method_2")
        self.assertTrue(os.path.exists(self.temp_file.name))

# nose2 -v test_fixture_example.py で実行すると、各フィクスチャの実行順序が確認できます。

レイヤー (Layers) – より高度なフィクスチャ管理

nose2 には「レイヤー」という、より高度なフィクスチャ管理の仕組みがあります。これは Zope Testrunner との互換性のために導入された概念で、フィクスチャの依存関係や構成をより柔軟に定義できます。

レイヤーを使用するには、nose2.plugins.layers プラグインを有効にする必要があります(設定ファイルで plugins に追加)。レイヤーはクラスとして定義し、特定のテストクラスやテストメソッドに適用できます。

複雑なセットアップや、複数のテストスイート間で共通のセットアップ手順を共有したい場合に役立ちますが、通常のフィクスチャで十分な場合が多いでしょう。詳細は公式ドキュメントを参照してください。

テストの核心は、コードの実際の出力や状態が期待通りであるかを確認することです。この確認を行うのがアサーションです。

nose2unittest.TestCase をベースにしているため、unittest が提供する豊富なアサーションメソッドをそのまま利用できます。

メソッド チェック内容
assertEqual(a, b) a == b であることを確認
assertNotEqual(a, b) a != b であることを確認
assertTrue(x) bool(x)True であることを確認
assertFalse(x) bool(x)False であることを確認
assertIs(a, b) a is b であること(同一オブジェクトであること)を確認
assertIsNot(a, b) a is not b であることを確認
assertIsNone(x) x is None であることを確認
assertIsNotNone(x) x is not None であることを確認
assertIn(a, b) a in b であることを確認
assertNotIn(a, b) a not in b であることを確認
assertIsInstance(obj, cls) isinstance(obj, cls) であることを確認
assertNotIsInstance(obj, cls) not isinstance(obj, cls) であることを確認
assertRaises(exception, callable, *args, **kwds) callable(*args, **kwds) を呼び出すと指定した exception が送出されることを確認 (コンテキストマネージャとしても利用可能)
assertRaisesRegex(exception, regex, callable, *args, **kwds) 指定した例外が送出され、そのエラーメッセージが正規表現 regex にマッチすることを確認
assertWarns(warning, callable, *args, **kwds) callable を呼び出すと指定した warning が発生することを確認
assertAlmostEqual(a, b, places=7) ab が指定した小数点以下の桁数 (places) まで等しいことを確認
assertNotAlmostEqual(a, b, places=7) ab が指定した小数点以下の桁数まで等しくないことを確認
assertGreater(a, b) a > b であることを確認

これらのアサーションメソッドを適切に使うことで、テストの意図が明確になり、失敗した場合の原因特定が容易になります。

Tips: pytest ではシンプルな assert 文を使うのが一般的ですが、nose2 (および unittest) では、より具体的なアサーションメソッド (assertEqual, assertTrue など) を使うことが推奨されます。これにより、失敗時のエラーメッセージがより詳細になります。

プラグインシステム

nose2 の最大の強みの一つが、その柔軟で強力なプラグインシステムです。テストのロード、実行、結果報告など、テストプロセスの様々な段階にフックし、機能を追加・変更することができます。

多くの便利な機能が標準プラグインとして提供されており、設定ファイルやコマンドラインオプションで簡単に有効化できます。

主要な標準プラグイン

プラグインモジュール 設定セクション 主な機能 有効化
nose2.plugins.coverage [coverage] テストカバレッジ計測とレポート生成 (coverage ライブラリが必要)。HTMLレポートやコンソール出力、不足行表示などが可能。 --with-coverage または設定ファイルで always-on = True
nose2.plugins.mp [multiprocess] テストを複数のプロセスに分散して並列実行し、実行時間を短縮。CPUバウンドまたはI/Oバウンドなテストが多い場合に効果的。 --plugin nose2.plugins.mp-N <プロセス数> または設定ファイル
nose2.plugins.logcapture [log-capture] テスト実行中のログメッセージをキャプチャし、失敗したテストのレポートに追加。デバッグに役立つ。 --log-capture または設定ファイルで always-on = True
nose2.plugins.layers [layers] Zope スタイルのレイヤーフィクスチャをサポート。高度なフィクスチャ管理が可能。 --plugin nose2.plugins.layers または設定ファイル
nose2.plugins.junitxml [junit-xml] テスト結果を JUnit XML 形式で出力。CI/CD ツールとの連携に便利。 --junit-xml または設定ファイル
nose2.plugins.prof [profiler] Python のプロファイラ (cProfile) を使用してテスト実行のパフォーマンスを計測。 --profile または設定ファイル
nose2.plugins.testid [testid] 各テストに一意なIDを割り当て、IDを指定して特定のテストを実行可能にする。 (デフォルトで有効なことが多い)
nose2.plugins.attrib [attrib] テスト関数やクラスに属性 (attribute) を付与し、属性に基づいてテストを選択実行 (`-A` オプション)。 --plugin nose2.plugins.attrib または設定ファイル
nose2.plugins.dundertest (なし) __test__ = False が設定されたクラスやモジュールをテスト対象から除外する。 (デフォルトで有効)

プラグインの有効化方法

プラグインを有効にする方法はいくつかあります:

  1. コマンドラインオプション: 多くのプラグインは専用のコマンドラインスイッチを持っています (例: --with-coverage, --log-capture)。
  2. --plugin オプション: --plugin <モジュール名> で特定のプラグインをロードします (例: --plugin nose2.plugins.mp)。
  3. 設定ファイルの [unittest] セクション: plugins キーにロードしたいプラグインのモジュール名をリスト形式で記述します。
  4. 設定ファイルのプラグインセクション: 各プラグインに対応するセクション (例: [coverage]) で always-on = True と設定すると、そのプラグインが常に有効になります。

サードパーティプラグイン

標準プラグイン以外にも、サードパーティ製のプラグインが存在します。例えば、テスト結果をHTML形式で出力する nose2-html-report などがあります。これらのプラグインもpipでインストールし、設定ファイルで有効化することで利用できます。

pip install nose2-html-report
[unittest]
plugins = nose2_html_report.html_report

[html-report]
always-on = True
path = test_report.html # 出力ファイルパス

プラグインシステムを活用することで、nose2 をプロジェクトのニーズに合わせて柔軟に拡張していくことが可能です。

コマンドラインオプション

nose2 は豊富なコマンドラインオプションを提供しており、テストの実行方法を柔軟に制御できます。設定ファイルでも多くの設定が可能ですが、一時的な変更や特定の実行シナリオではコマンドラインオプションが便利です。

よく使われるオプションをいくつか紹介します。完全なリストは nose2 --help で確認できます。

オプション 短縮形 説明
--verbose -v 詳細な出力モード。実行中のテスト名などを表示します。複数指定 (-vv, -vvv) でさらに詳細度が上がります。
--quiet -q 静かな出力モード。成功したテストの情報などを抑制します。
--fail-fast -F 最初のテスト失敗またはエラーが発生した時点でテスト実行を停止します。
--start-dir DIRECTORY -s DIRECTORY テスト探索を開始するディレクトリを指定します (デフォルト: .)。
--config FILE -c FILE ロードする設定ファイルを指定します。複数指定可能です。
--no-user-config ユーザーのホームディレクトリにある設定ファイル (~/.unittest.cfg, ~/.nose2.cfg) をロードしません。
--log-level LEVEL nose2 自身のログレベルを設定します (DEBUG, INFO, WARNING, ERROR, CRITICAL)。デバッグ時に役立ちます。
--plugin MODULE 指定したプラグインモジュールをロードします。
--no-plugins すべてのプラグインをロードしません(テストの発見や実行ができなくなるため注意)。
TEST_NAMES... 実行したいテストの名前を指定します。モジュール名、クラス名、メソッド名、ファイルパスなどを指定できます (例: test_module, test_module.TestClass, test_module.TestClass.test_method)。
プラグイン固有のオプション (例)
--with-coverage カバレッジプラグインを有効にします (nose2.plugins.coverage)。
--coverage-report TYPE カバレッジレポートの種類を指定します (term, term-missing, html, xml など)。複数指定可能。
--coverage-config FILE カバレッジの設定ファイル (.coveragerc) を指定します。
--processes NUM -N NUM 並列実行するプロセス数を指定します (nose2.plugins.mp)。0 を指定するとCPUコア数になります。
--log-capture ログキャプチャプラグインを有効にします (nose2.plugins.logcapture)。
--junit-xml JUnit XML レポートプラグインを有効にします (nose2.plugins.junitxml)。
--attribute ATTR_EXPR -A ATTR_EXPR 属性 (attribute) に基づいてテストを選択実行します (nose2.plugins.attrib)。(例: -A "not slow")
--pretty-assert アサーション失敗時の差分表示をより見やすくします (nose2.plugins.prettyassert)。

これらのオプションを組み合わせることで、特定のテストだけを実行したり、デバッグ情報を増やしたり、CI環境向けに出力を調整したりと、様々な状況に対応できます。

unittest との互換性

nose2unittest の「後継」および「拡張」として設計されているため、unittest との互換性は非常に高いです。

  • テストケースの記述: unittest.TestCase を継承して書かれたテストクラスやテストメソッドは、そのまま nose2 で認識・実行されます。
  • アサーションメソッド: assertEqual(), assertTrue(), assertRaises() など、unittest のアサーションメソッドはすべて利用可能です。
  • フィクスチャ: setUp(), tearDown(), setUpClass(), tearDownClass(), setUpModule(), tearDownModule() といった unittest のフィクスチャメカニズムがそのまま動作します。
  • テストスキップ: unittest.skip(), unittest.skipIf(), unittest.skipUnless() デコレータや、unittest.TestCase.skipTest() メソッドによるテストのスキップもサポートされています。
  • サブテスト: Python 3.4 で導入された unittest のサブテスト (with self.subTest(i=i): ...) も nose2 で利用可能です。

基本的に、標準の unittest フレームワークで書かれたテストスイートは、特別な変更なしに nose2 で実行できるはずです。これにより、既存の unittest ベースのプロジェクトに nose2 を導入し、プラグインによる機能拡張(カバレッジ計測、並列実行など)の恩恵を受けることが容易になります。

ポイント: nose2unittest の機能に加えて、独自の機能(パラメータ化テスト、レイヤーフィクスチャ、豊富なプラグインなど)を提供します。unittest から nose2 に移行する主なメリットは、これらの追加機能を利用できる点にあります。

ただし、オリジナルの nose とは一部互換性のない点があるため、nose から nose2 への移行には注意が必要です。詳細は公式ドキュメントの “Differences: nose2 vs nose vs unittest2” を参照してください。

pytest との比較

Python のテストフレームワークを選ぶ際、nose2 と並んで、あるいはそれ以上に有力な選択肢となるのが pytest です。どちらも高機能なフレームワークですが、設計思想やコミュニティの状況に違いがあります。

特徴 nose2 pytest
ベース unittest の拡張 独自(unittest テストも実行可能)
テスト記述スタイル unittest.TestCase クラスベースが基本。関数ベースも可。 シンプルな関数ベースが主流。クラスも利用可能。
アサーション self.assertEqual() など unittest のメソッドを使用 標準の assert 文を使用(詳細な失敗情報を提供)
フィクスチャ setUp/tearDown 系メソッド、レイヤープラグイン より強力で柔軟な専用のフィクスチャ機構(デコレータベース @pytest.fixture
パラメータ化 @nose2.tools.params デコレータ @pytest.mark.parametrize デコレータ(より高機能)
プラグインシステム あり(標準プラグイン+サードパーティ) 非常に活発で豊富なプラグインエコシステム (800以上)
コミュニティとメンテナンス 比較的小規模、メンテナンスは継続中 大規模で非常に活発、多くのコントリビューター
学習コスト unittest 経験者には容易。プラグインは別途学習。 シンプルで始めやすいが、高機能なフィクスチャなどを使いこなすには学習が必要。
推奨度 (公式) 新しいプロジェクトには pytest を推奨 広く推奨されている

どちらを選ぶべきか?

  • nose2 が適している可能性のあるケース:
    • 既存のプロジェクトが unittest を深く利用しており、互換性を最優先したい場合。
    • オリジナルの nose からの移行を検討している場合(ただし非互換性に注意)。
    • unittest スタイルのテスト記述に慣れており、それを維持したい場合。
  • pytest が多くの場合推奨される理由:
    • 簡潔な記述: テストコードがよりシンプルになり、ボイラープレートコードが少ない。
    • 強力なフィクスチャ: 依存性の注入やスコープ管理など、柔軟なセットアップ・ティアダウンが可能。
    • 豊富なプラグイン: Webフレームワーク連携、非同期テスト、BDDサポートなど、あらゆるニーズに対応するプラグインが見つかる可能性が高い。
    • 活発なコミュニティ: 情報が多く、問題解決がしやすい。将来性も高い。
    • 詳細なアサーション: 標準の assert 文で、失敗時に変数の値などが詳細に表示される。

nose2 の公式ドキュメント自体が、新しいプロジェクトには pytest を検討することを推奨している点を考慮すると、特別な理由がない限り、現在では pytest を選択する方がメリットが多いと言えるでしょう。

しかし、nose2 も依然としてメンテナンスされており、特定のユースケースでは有効な選択肢です。両者の特徴を理解した上で、プロジェクトの状況に合わせて最適なフレームワークを選択することが重要です。

発展的な使い方

nose2 は基本的なテスト実行機能に加え、いくつかの発展的な機能も提供しています。

パラメータ化テスト (Parameterized Tests)

同じテストロジックを異なる入力値や期待値で繰り返し実行したい場合、パラメータ化テストが便利です。nose2 では nose2.tools.params デコレータを使います。

# test_parameterized.py
import unittest
from nose2.tools import params
from mymath import add # add(a, b) をテスト

class ParameterizedTest(unittest.TestCase):

    @params(
        (1, 2, 3),
        (-1, 1, 0),
        (0, 0, 0),
        (100, 200, 300),
        (-5, -10, -15)
    )
    def test_add_parameterized(self, a, b, expected):
        """add(a, b) == expected をテスト"""
        print(f"Testing add({a}, {b}) == {expected}") # 実行確認用
        self.assertEqual(add(a, b), expected)

# 実行: nose2 -v test_parameterized.py
# 結果: 5つのパラメータセットそれぞれに対してテストが実行される

@params に渡す引数は、テストメソッドに渡されるパラメータのタプル(または単一の値)のシーケンスです。各タプルが1回のテスト実行に対応します。関数に対しても同様に適用できます。

テストの属性付けと選択実行 (Attribute Plugin)

テストに特定の属性(マーカーやタグのようなもの)を付与し、その属性に基づいて実行するテストを選択できます。これには nose2.plugins.attrib プラグインが必要です。

設定ファイルでプラグインを有効にします:

[unittest]
plugins = nose2.plugins.attrib

[attrib]
always-on = True

テストコード内で属性を付与します:

# test_attributes.py
import unittest
import time

def slow_test(func):
    """テストに 'slow' 属性を付与するデコレータ"""
    func.slow = True
    return func

class AttributeTest(unittest.TestCase):

    def test_fast_operation(self):
        # 通常の(速い)テスト
        self.assertTrue(True)

    @slow_test
    def test_slow_operation(self):
        # 時間のかかるテスト('slow' 属性を持つ)
        print("Running slow test...")
        time.sleep(2)
        self.assertTrue(True)

    def test_another_fast_one(self):
        self.assertEqual(1 + 1, 2)

# 実行例:
# 全てのテストを実行: nose2 test_attributes.py
# 'slow' 属性を持たないテストのみ実行: nose2 -A "not slow" test_attributes.py
# 'slow' 属性を持つテストのみ実行: nose2 -A "slow" test_attributes.py

-A (または --attribute) オプションにPythonの式を渡すことで、実行するテストをフィルタリングできます。"slow"slow=True を意味し、"not slow"slow 属性がないか、slow=False であるテストを選択します。これにより、実行に時間のかかるテストを普段はスキップする、といった運用が可能になります。

テストスイートのカスタマイズ

nose2unittestload_tests プロトコルをサポートしています。テストモジュール内に load_tests(loader, standard_tests, pattern) という名前の関数を定義することで、そのモジュールからロードされるテストスイートをカスタマイズできます。これにより、テストの順序を制御したり、特定の条件下でのみテストを追加したりといった、より高度なテストローディングロジックを実装できます。

これらの発展的な機能を活用することで、より効率的で管理しやすいテスト環境を構築できます。

まとめ

nose2 は、Python標準の unittest フレームワークを拡張し、多くの便利な機能を提供するテストランナーです。特に、強力なプラグインシステム、柔軟なテストディスカバリ、設定ファイルによるカスタマイズ性は大きな利点です。

unittest に慣れている開発者にとっては導入しやすく、カバレッジ計測、並列実行、パラメータ化テストといった機能を簡単に追加できます。

一方で、現在のPythonテストエコシステムにおいては、pytest がデファクトスタンダードとしての地位を確立しており、より活発なコミュニティ、豊富なプラグイン、簡潔な記述スタイルといった点で優位性があります。nose2 自身も新しいプロジェクトには pytest を推奨しています。

nose2 を検討する主な理由:

  • 既存の unittest ベースのプロジェクトに機能を追加したい。
  • unittest のテスト記述スタイルを維持したい。
  • nose からの移行(ただし互換性に注意)。

注意点:

  • pytest と比較するとコミュニティやプラグインの規模は小さい。
  • オリジナルの nose とは完全な互換性はない。

nose2 は依然として有用なツールですが、フレームワークを選択する際には、pytest と比較検討し、プロジェクトの要件やチームのスキルセットに合ったものを選ぶことが重要です。この解説が、nose2 の理解と適切なテストフレームワーク選択の一助となれば幸いです。 Happy Testing!