はじめに: 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]
基本的なテストの書き方と実行
nose2
は unittest
をベースにしているため、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
を含むディレクトリ、lib
やsrc
という名前のディレクトリも探索対象になります。 - ファイル名: 名前の先頭が
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 |
test-file-pattern | テストモジュールとして認識するファイル名のパターン (glob形式)。 | test*.py | *_test.py |
test-method-prefix | テストメソッド/関数として認識する名前の接頭辞。 | test | check_ |
plugins | 追加でロードするプラグインのモジュール名をリスト形式で指定します(改行区切り)。 | なし | nose2.plugins.layers |
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)
テストを実行する際には、テストの前処理(セットアップ)や後処理(ティアダウン)が必要になることがよくあります。例えば、テスト用のデータベース接続を確立したり、一時ファイルを作成したり、テスト後にそれらをクリーンアップしたりする場合です。nose2
は unittest
のフィクスチャ機能をそのまま利用できます。🧹
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
に追加)。レイヤーはクラスとして定義し、特定のテストクラスやテストメソッドに適用できます。
複雑なセットアップや、複数のテストスイート間で共通のセットアップ手順を共有したい場合に役立ちますが、通常のフィクスチャで十分な場合が多いでしょう。詳細は公式ドキュメントを参照してください。
アサーション (Assertions)
テストの核心は、コードの実際の出力や状態が期待通りであるかを確認することです。この確認を行うのがアサーションです。✅
nose2
は unittest.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) | a と b が指定した小数点以下の桁数 (places ) まで等しいことを確認 |
assertNotAlmostEqual(a, b, places=7) | a と b が指定した小数点以下の桁数まで等しくないことを確認 |
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 が設定されたクラスやモジュールをテスト対象から除外する。 | (デフォルトで有効) |
プラグインの有効化方法
プラグインを有効にする方法はいくつかあります:
- コマンドラインオプション: 多くのプラグインは専用のコマンドラインスイッチを持っています (例:
--with-coverage
,--log-capture
)。 --plugin
オプション:--plugin <モジュール名>
で特定のプラグインをロードします (例:--plugin nose2.plugins.mp
)。- 設定ファイルの
[unittest]
セクション:plugins
キーにロードしたいプラグインのモジュール名をリスト形式で記述します。 - 設定ファイルのプラグインセクション: 各プラグインに対応するセクション (例:
[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 との互換性
nose2
は unittest
の「後継」および「拡張」として設計されているため、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
を導入し、プラグインによる機能拡張(カバレッジ計測、並列実行など)の恩恵を受けることが容易になります。
ポイント: nose2
は unittest
の機能に加えて、独自の機能(パラメータ化テスト、レイヤーフィクスチャ、豊富なプラグインなど)を提供します。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
であるテストを選択します。これにより、実行に時間のかかるテストを普段はスキップする、といった運用が可能になります。⏳
テストスイートのカスタマイズ
nose2
は unittest
の load_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! 🎉
コメント