python

Python nose2のDSL記法でシンプルに単体テストを書く

Pythonのテストフレームワークだと、unittestやpytestが有名です。

今回は、nose2というPythonのテストフレームワークを紹介します。

unitestやpytestより強力なのでぜひ、本記事を読んで見て使っていただきたいです。

 

  • nose2についてざっくり知る
  • nose2の記法や設定について知る​

nose2とは

Pythonのテストフレームワークの一つ。

nose2の狙い

公式ドキュメントを意訳してみました。

  • 良いAPIを提供する
  • ユーザー設定を簡単にする
  • シンプルなインターフェースとプロセス
  • 同じコードでpython2と3をサポートする
  • 開発コミュニティの促進

少し、抽象的でよくわからないですね。

unittestとnose2を比較したメリット・デメリット

nose2のメリット

nose2はカバレッジが取得できる

テストの網羅性がどれだけあるのかを​測ってくれます。

Name Stmts Miss Cover
---------------------------------------
app.py 364 281 23%
test/load_env.py 5 0 100%
test/pathmagic.py 3 0 100%
test/test_app.py 61 22 64%
test/test_test.py 18 0 100%
---------------------------------------
TOTAL 451 303 33%

​nose2はDSL記法で書ける

assertXXXとか使わなくてもいい???

 

nose2のデメリット

nose2は設定が面倒

カスタマイズ性とトレードオフなので、デメリットにあげるか迷いました。

ログの出力など自分で設定してあげたりする項目が多い。

上級者向けな気がします。

 

nose2はドキュメントが整ってない

ドキュメントはあるにはあるんですが、サポートが薄いです。

ほぼ、プラグインや設定周りに割かれていて肝心のテストの書き方の説明がない。

unittestやpytestを経験してきた人たち向けって感じがします。

nose2の使い方

nose2は命名規則

nose2で実行されるファイルやディレクトリ、メソッド名等には命名規則があります。

  • __init__.pyを含む
  • 小文字のtestを含むディレクトリ
  • ディレクトリ名は、`src`もしくは`lib`

ファイル名はtestで始まっていること

test.py
test_views.py
test_models.py
testThingy.py

以下のパターンは動かない

not_a_test.py
myapp_test.py
some_test_file.py

​テストモジュールにおいて、nose2は`class:unittest.TestCase`とtestとついた関数から読まれる。​

 

nose2の実行方法

サンプルのフォルダ構成

sample_dir
├ app.py
├ test
│ └ test_app.py 
└ nose2.cfg

sample_dir配下で実行​

nose2 --verbose -C

​DSL記法サンプル

普通の書き方は、unittestとかpytestととほぼ変わらないので省略。

`注意:`厳密にはunittestと同じではないため、サポートされていなかったり、レポートロジックなど自分で設定して上げる必要があります。

from  nose2.tools  import such

​
# classと同じ
with such.A('sample test') as it:
    # テスト実行時に1回実行
    @it.has_setup
    def setup():
        global a
        global something
        a = 1
        something = 'a value'
​
    # テスト関数読むたびに実行
    @it.has_test_setup
    def setup_each_test_case():
        b = a + 1
​
    # グループ化
    with it.having('group'):
        @it.should('sum numbers')
        def test1(case):
            it.assertEqual(1 + 1, 2)
​
        @it.should("be able to use the scenario's assert methods")
        def test2():
            it.assertEqual(something, 'a value')
​
        @it.should("optionally take an argument")
        def test3(case):
            case.assertEqual('some value', 'some value')
​
it.createTests(globals())

ほぼ、unittestの使い方と同じです。
なので、unittestからの移行も低いです。

pytestの記法でも書けます。とりあえず、入れて見ても動くので使ってみてください!

 

ABOUT ME
ロッピー
コンサルタントから2018年にエンジニアに転向。年収400万円のサラリーマンエンジニアから、半年で月収100万円を稼ぐエンジニアになった。 Python、Golangなど単価の高い言語を得意とする。