Pythonのテスト環境

pythonのテスト環境についてちょっと調べてみたのでまとめ

py.test vs nose vs unittest

だいたい人気のあるtesting frameworkはこの3つ。

testing framework
説明
py.test テストの自動探索/実行機能などがあり、簡単に使える。黒魔術に頼っていたためにnoseというクローンが作られ、人気の座を奪われた。
nose 一番人気。python組み込みのunittest上に構築されているのも特徴。
unittest Pythonの組込みモジュール。xUnit型。unittest 2ではテストの自動探索機能などが追加されている。

歴史的には

  1. 2000年: Kent BeckがJUnitをリリース
  2. 2001年: xUnitの1つとしてunittestがPython 2.1に組み込まれる。
  3. ???: py.test リリース。この時点でテストの自動探索/実行機能を装備していたかは不明。
  4. ???: py.test 0.8の時点でメタプログラミングだらけの「黒魔術」が原因?でnoseがcloneとして作られる。noseが最初からunittest上に作られていたかは不明。
  5. 2010年: unittest2 リリース。自動探索機能を搭載。

など、各々便利な機能を取り込んで発展してきたもよう。

  • 活発に使われていること
  • 出自が「コードの汚さへの反発」というポジティブな目的があること
  • 組込みモジュールのunittestのテストを実行できるという柔軟さ

から、noseを使うのが良いと思う。

リポジトリ内での使い方

Jupyter notebookのレンダリングを行う公式webアプリであるnbviewerでの使い方が綺麗( https://github.com/jupyter/nbviewer/blob/master/tasks.py )。

travis-ci + invoke (Pythonのタスクランナー) + nose

という構成。

ここでは、

  1. travis ciを使用(.travis.ymlを実行)
    1. .travis.ymlでinvokeを使用して環境のセットアップやtestコマンドを外部ファイル化(tasks.py)
    2. pipのパッケージはrequirements.txtとして外部ファイル化。
    3. テストに必要なパッケージのインストールはrequirements-dev.txtとして分離。
  2. invokeでtasks.pyを実行
  3. tasks.pyの内部でnosetestsでテストを実行

という流れで自動テストを実行している。(なお、jupyter notebookのレポジトリではtravis ciだけでなくcircle ciも使っている)

このような構成とすることで、以下のメリットが得られる:

  • invokeでテストの一括実行が出来るようにすることで、ciサービス(ローカルでの手動実行も含め)間の差異を環境設定ファイルだけにとどめている。
  • テストだけでない環境構築等のタスクもinvokeとしてモジュール化できる。

構成サンプル


project_root
  |- app # アプリのディレクトリ
       |- tests
            |- test_*.py # テストコード
  |- .travis.yml
  |- tasks.py
  |- requirements.txt
  |- requirements-dev.txt
  |- Dockerfileなど
  • .travis.yml

language: python

python:
- '2.7'
- '3.3'
- '3.4'

before_install:
# テストに必要な環境を整える
- sudo apt-get update
- pip install -r requirements-dev.txt


install:
# アプリケーションに必要なパッケージをインストール
- pip install -r requirements.txt


script:
# テストの実行
- invoke test
  • tasks.py

import invoke

@invoke.task
def test(ctx):
    ctx.run("nosetests -v")
  • requirements-dev.txt

invoke
nose
  • app/tests/test_example.py (例)

#!/usr/bin/env python

def test_numbers_3_4():
    assert 3 * 4 == 12

参考

Leave a Comment

Your email address will not be published. Required fields are marked *