Pythonデバッガ(pdb)とテスト(pytest)についてのメモ

はじめに

今までテストを書くどころかデバッガを使ったことがなかったのですが、id:Kesinさんの↓の記事を読んで、このままではマズイと思ったので勉強しました。


デバッガ

Pythonには標準でpdbというデバッガが付いてるらしい。

こちらによると、

使い方はいろいろあるみたいだけど、とりあえず set_trace は便利なのですぐにでも使ってみるべき。pdb.set_trace() でデバッグ用の対話シェルが実行される。

とのこと。他のサイトでもプログラムの気になる所にpdb.set_trace()を埋め込んで使っていました。

import pdb
pdb.set_trace()

使い方

↑の命令を見ながらやっていきます。基本的にはnsで処理を進めながら、気になるところでp 変数名を入力して変数の中身を見るみたいな感じでいいみたいです。とりあえずprintデバッグぐらいのことは簡単に出来るみたい。 ちょうど期待通りに動かなかったプログラムがあったので、pdbデバッグしてみました。簡単です!

ipdb

ipdbというのを使えば、ipythonライクに使えるらしい。こっちのほうがいいなとか思ってたら、PudBというもっと良さそうなのがあった。

PudB

pdbでは補完機能がないため、変数名を全部打たないといけなかったり結構面倒でした。そんな中↓の記事を見つけました。ipdbを使えば補間などがあるらしいですがPudBというのが変数の中身やソースコードなど、いろいろと可視化されたものが使えてなにやらipdbよりも便利らしい。

インストールはpipから簡単に出来ました.

$ pudb ファイル名

で起動できるらしい。 さっきのpdbの勉強した時と違ってプログラムを書き換えなくても簡単に使えるみたい、コレは嬉しい。(もしかしたらpdbでも同じようにできるのかも?試しにpdb ファイル名を打ってみたけど、Command not foundでした)

(追記:python -m pdb ファイル名で同じように使えるようです)

f:id:nwpct1:20140326143329p:plain

起動すると設定画面に入る.「行番号の表示」とShellを「ipython」, Themeを「dark vim」に変更した。それ以外はとりあえずデフォルトのまま使ってみる

使い方

分からなかったら?を入力すればhelpが現れるという便利機能がある。コレは僕みたいな初心者には嬉しい機能。

ブレークポイントってなんだろう?って思ったので調べてみた。

上のサイトでブレークポイント以外にも色々解説されてました。一度真似してみるとだいぶデバッガを使いこなせそうです。

後でやってみよう。。。とりあえずデバッガは使いながら慣れていくとしてテストについて勉強する。


テストについて

Pythonにおけるテストツールは、どれを使えばいいのか悩んでたら↓の記事を見つけました。

テスト管理ツールとしてはtoxが一番楽かなあと思います。toxは複数の環境(異なるPythonのバージョン、異なるパッケージのバージョン)などを一気にテストしてくれるツールで、こいつもvirtualenvを使ってテスト用の環境を作ってくれます。

toxはpy.testと同じプロジェクトチームなので相性がいい。

複数の入力データを与えるテストを行う場合、どちらのライブラリも機能的には同じようにテストできますが、結果レポートの分かりやすさ・デバッグのしやすさを考慮すると pytest の方が使い勝手が良いと私は思いました。

なるほどtoxとpytestというのを使うのがいいみたいです。他にもunittestというのがあるみたいなのですが、pytestの方がテストにコケたときの情報が詳しかったりなんか良さそうです。

pytestを動かしてみる

まずはpipでインストールしてドキュメントのプログラムを動かしてみる。

def func(x):
    return x + 1

def test_answer():
    assert func(3) == 5

というプログラムをtest.pyで保存して↓のように動かしてみた。

$ py.test
============================ test session starts ============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
collected 0 items

=============================  in 0.01 seconds ==============================

あれっ?collected 0 itemsとなってる。名前を変えてみると

$ mv test.py test_sample.py
$ py.test
============================ test session starts ============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
collected 0 items / 1 errors

================================== ERRORS ===================================
______________________ ERROR collecting test_sample.py ______________________
../../.virtualenvs/analysis/lib/python2.7/site-packages/_pytest/python.py:451: in _importtestmodule
>           mod = self.fspath.pyimport(ensuresyspath=True)
../../.virtualenvs/analysis/lib/python2.7/site-packages/py/_path/local.py:620: in pyimport
>           __import__(modname)
E             File "/Users/masashi/PycharmProjects/data_analysis/test_sample.py", line 1
E           SyntaxError: Non-ASCII character '\xe3' in file /Users/masashi/PycharmProjects/data_analysis/test_sample.py on line 1, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
========================== 1 error in 0.05 seconds ==========================

おぉなんかテストしてる。基本的には test_ の接頭辞をもつファイルや関数でないとダメらしい。ドキュメントにテスト探索ルールの節があったから後で読もう。

一つのクラスで複数のテストをグループ化

テストを書き始めて何個か作成したら、クラスやモジュール内にそういったテストをグループ化すると分かりやすくなります。2つのテストを含むクラスを作成しましょう。サブクラス化する必要はありません。単純にそのファイル名を与えることで、対象のモジュールを実行できます。

なるほど

class TestClass:
    def test_one(self):
        x = "this"
        assert 'h' in x

    def test_two(self):
        x = "hello"
        assert hasattr(x, 'check')

ちなみにhasattr()メソッドはオブジェクトと文字列を引数にとり、文字列がオブジェクトの属性名の一つであった場合 True を、そうでない場合 False を返すそうです。この場合最初のテストは成功し、2番目のテストは失敗するらしい。

使用方法

ドキュメントに詳しく載ってた。これは一度全部見たほうが良さそう。 特に気になったのだけメモ。

  • 失敗したときにエラー箇所でPDB (Python デバッガー) を起動
$ py.test --pdb

これは便利そう。

ブレークポイントを設定して pdb.set_trace() を行いたいなら、ヘルパー関数を使える

import pytest
def test_function():
    ...
    pytest.set_trace()    # PDB デバッガーを起動してトレースする
  • 様々なオプション
$ py.test -x            # 最初に失敗したときに中止
$ py.test --maxfail=2   # 2 回失敗したときに中止
$ py.test test_mod.py   # モジュール内のテストを実行
$ py.test somepath      # 指定したパスの全てのテストを実行
$ py.test -k string     # string を含む名前をもつテストのみを実行
$ py.test --pyargs pkg  # pkg のディレクトリ配下にある全てのテストを実行

他にもPythonコードからのpytestの呼び出しとかも載ってた。

pytest.vimというvimプラグインが便利らしいのである程度書けるようになったらチェックしよう。

toxでPython2/3両対応のテストの実行

toxの勉強までしたかったんだけど、まだpytestをどのように書くのかが分かってないのでやめておく。


終わりに

pytestでどのようにテストを書いていくのかがわからない。ある程度、メソッドの引数や返り値が決まっているようなコードのテストなら今の段階でも書けそうだけど、実際書くプログラムでそんなパターンってそんなに多くない気がする。

まだテスト自体がよく分からない。↓の記事を読むと、テストの勉強には写経がいいらしい。

とりあえず下の本を注文してみた。レビューがあまり高くないからちょっと悩んだけど、↑のhirokiさんをはじめ、TDDに精通している多くの人が推薦してるらしい。実際に「python テスト駆動開発 写経」でぐぐってみるとケント・ベックのこの本ばかりだった。

和田卓人さんはテスト駆動開発入門をRubyで写経しながら、Rubyを学んでいったらしいです。

テスト駆動開発入門

テスト駆動開発入門

  • 作者: ケントベック,Kent Beck,長瀬嘉秀,テクノロジックアート
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2003/09
  • メディア: 単行本
  • 購入: 45人 クリック: 1,058回
  • この商品を含むブログ (161件) を見る