先日リリースされたPython 2.7がなかなかいいかんじ。set型のリテラル,set/辞書内包表記やviewなど3.xからのバックポートを多く含んでいる。細かいところではネットワーク系モジュールのIPv6対応が進んでいたり,Python 2系最後のリリースとうたわれているだけあって,かなり意欲的なリリースとなっている。
なかでも,標準のunittestモジュールがものすごく大きな進化を遂げていて,かなり魅力的になっているので簡単に紹介したいと思う。
テストディスカバリ
単体テストは,たいていモジュールやクラス,または機能ごとに個別にファイルを作り,テストコードを書く。大抵のプロジェクトでは,複数のテスト用ファイルが存在することになる。2.6までのunittestモジュールでは,テスト用のプログラムファイルを個別に指定してテストを行う必要があった。これがけっこう面倒で,たいていの人はnoseのようにプロジェクトに存在するテストコードを探し出して自動実行してくれる(テストディスカバリ)機能を持ったツールを併用していた。
新しいunittestモジュールには,テストディスカバリ機能が内蔵されるようになった。以下のようにしてPythonを起動すると,プロジェクトから自動的にテストを見つけ出して順次実行してくれる。
python -m unittest discover
新しいassertメソッド
テスト時に利用するassertメソッドの種類が比較的少なかったことも旧unittestモジュールの欠点だったけど,新しいunittestモジュールでは大幅に増量されている。
- assertGreater / assertLess / assertGreaterEqual / assertLessEqual
- assertRegexpMatches / assertNotRegexpMatches - 正規表現を使ったテキストマッチ
- assertIn / assertNotIn – 特定のシーケンスに含まれるかどうかを検査
- assertIs / assertIsNot - 同一オブジェクトかどうかを検査
- assertIsNone / assertIsNotNone
- assertIsInstance / assertNotIsInstance
- assertDictContainsSubset
- assertSequenceEqual
- assertItemsEqual - 順番を考慮せずシーケンスを検査
Pythonicな機能追加
これが一番クールだと思う:-)。
たとえばassertRaisesでwithを使えるようになった。assertRaisesのように,例外が出るかどうかを検査したいとき,普通に考えると
assertRaises(例外,関数オブジェクト,引数...)
のように書く必要がある。「assertRaises(ValueError, test_func(foo, bar, baz))」のように書いてしまうと,assertRaises()の呼び出し時に例外を発生する関数が呼ばれてしまって,例外がassertメソッドの外に出て行ってしまうからだ。新unittestでは,withを使って以下のように書ける。
with self.assertRaises(TypeError):
check_func(2, '3')
こっちの書き方の方が,すっきりしてるし,揺るぎがなく,よりPythonicだ。
もうひとつ。テストのスキップにデコレータが使える。
@skipIf(sys.version_info[2] < 5, "only Python > 2.5")
def test_method(self):
...
その他,モジュールレベルでsetUP,tearDownができるようになっていたり,かなり機能強化されて使いやすくなっている。
App Engineやフレームワークの縛りがあって2.7が使えない人や,プラグイン依存でnoseなどを使い続けたい人は,unittest2を使うと同等の機能を利用できる。