読み進めた本

テスト駆動Python [asin:B07F65PFZN:detail]

pytest とは何か

  • ソフトウェアテストフレームワーク。
  • 既存の unittest/nose などと比較して、テストが読みやすい。
  • 単純なテストを書くのが簡単。
  • 複雑なテストを書くのも簡単。
  • unittest/nose のテストを pytest でも実行できる。

サンプルソース

本書のコードは公開されている。 ※もちろんこれだけでは意味が分からないので、本の購入は必要。 [https://pragprog.com/titles/bopytest]

本書のサンプルコードを実行するにあたり作成した環境

私個人の実行環境であり、本の内容とは関係ない。 Windows の WSL2 環境で検証。 WSL2 の中身は Ubuntu。

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.1 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.1 LTS"
VERSION_ID="20.04"
$ python -V;pipenv --version;pytest --version
Python 3.8.2
pipenv, version 2020.8.13
pytest 6.1.0

pipenv を利用した仮想環境の場合

各個人の環境に依存。 私の場合は、今回はpipenvを利用して仮想環境を構築した。

$ pip3 install pipenv --user
$ pipenv install pytest
##### pipenv の設定 #####
#.bashrc/.zshrcなどに追記する
## pipをユーザ権限でインストールしたときのライブラリの保存先にPathを通す
export PATH="$PATH:$HOME/.local/bin"

## pipenvで仮想環境を作るときにproject配下に.venvを作成
export PIPENV_VENV_IN_PROJECT=1

VSCode の設定

本書ではpytestのコマンドでテストを実行させていたが、VSCode の GUI でも実行できるためそちらを試した。

pytest を VSCode から実行できるようにする。

コマンドパレット(ctrl+shift+p)からpython configure testsを入力して設定を開く。

どのテストライブラリを利用するか選択。今回は本と同じ pytest を選択。

どこに test ファイルがあるのかを選択。

Chapter1 はじめての pytest

左側にフラスコのアイコンが現れるので、そこをクリックし、Run All Testsボタンを押下するとテストが実行される。

ターミナル(ctrl+shift+@)のPROGRAMSのタブにより具体的な結果が表示される。

show test output からtest_failingを確認することができる。
test_failingはなぜ失敗したのかの詳細セクション

assertについて

assertの後にbool値を返す式を書く。

def test_check():
    t = 1
    assert 1 == t
    assert (1, 2, 3) == (t, 2, 3)

サンプルコードの"namedtuple"について

例としてnamedtupleを使っていたが、知らない関数だったので調べた。
https://qiita.com/Seny/items/add4d03876f505442136

## こんな風に使う
>>> from collections import namedtuple
>>> Car = namedtuple('Car' , 'color mileage')

## 出力
>>> my_car = Car('red', 3812.4)
>>> my_car.color
'red'
>>> my_car.mileage
3812.4

※qiita から抜粋

雰囲気だけ理解して、本質ではないので次に進む。

サンプルコードでやっていること

Task オブジェクトを作成して、その挙動を test 関数を使って検証している。

from collections import namedtuple

# Taskというデータ型のフィールド'summary', 'owner', 'done', 'id'を定義
Task = namedtuple('Task', ['summary', 'owner', 'done', 'id'])

# デフォルト値を定義
Task.__new__.__defaults__ = (None, None, False, None)

# パラメータを指定しないときのデフォルト値(t1)がt2と一致するかのテスト
def test_defaults():
    t1 = Task()
    t2 = Task(None, None, False, None)
    assert t1 == t2

# namedtupleの.フィールド名が一致しているかテスト
def test_member_access():
    t = Task('buy milk', 'brian')
    assert t.summary == 'buy milk'
    assert t.owner == 'brian'
    assert (t.done, t.id) == (False, None)

pytest のオプション(紹介があったものだけ)

  • -v, –verbose
  • –collect-only
  • -k EXPRESSION
  • -m MARKERXPR
  • -x, –exitfirst
  • –maxfail=num
  • -s, –capture=method
  • –lf, –last-failed
  • –ff, –failed-first
  • -q, –quite
  • -l, –showlocals
  • –tb=style
  • –durations=N
  • –version
  • -h, –help

ディスカバリルール(実行するテストとして認識させるためのルール)

  • テストファイルは test_~~~ .py か ~~~_test.py 名前でないといけない。
  • テストメソッド、関数は test_~~~ でないといけない。( ~~テストはダメ?)
  • テストクラスは Test~~~ でないといけない。( ~~テストはダメ?)

pytestを引数なしで実行すると、上記のルールで書かれたファイル、関数、メソッド、クラスを探索されてテストコードが実行される。

感想

TDD がどんな感じなのか、雰囲気を理解した。続きは読み次第追記。

書籍

[asin:B07F65PFZN:detail]