株式会社クリアコード > ククログ

ククログ


Python用単体テストフレームワークPikzie 0.9.7リリース

Python用単体テストフレームワークであるPikzieのバージョン0.9.7をリリースしました。

ハイライト

CutterUxUと同じように、ついにPikzieでもデータ駆動テストをサポートしました。

データ駆動テスト前

例えば、今までこのように書いていたテストがあるとします。

test_prime.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
import pikzie

def test_zero():
    assert_false(is_prime(0))

def test_unit():
    assert_false(is_prime(1))

def test_small():
    assert_true(is_prime(2))

def test_square():
    assert_false(is_prime(4))

単体テストを書き始めたばかりの人は以下のように1つにまとめてしまうかもしれません。

test_prime.py:

1
2
3
4
5
6
7
import pikzie

def test_is_prime():
    assert_false(is_prime(0))
    assert_false(is_prime(1))
    assert_true(is_prime(2))
    assert_false(is_prime(4))

しかし、このような書き方はおすすめできません。異なるパターンのテストは別のテストにするべきです。そうすると、1つのパターンが失敗しても他のパターンはその影響を受けずに実行することができます。

例えば、is_prime(1)が失敗するとしましょう。そのとき、前者は以下のようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 実行される。パスする。
def test_zero():
    assert_false(is_prime(0))

# 実行される。失敗する。
def test_unit():
    assert_false(is_prime(1))

# 実行される。パスする。
def test_small():
    assert_true(is_prime(2))

# 実行される。パスする。
def test_square():
    assert_false(is_prime(4))

test_unit()が失敗しても他のパターンはテストできます。

一方、後者は以下のようになります。

1
2
3
4
5
def test_is_prime():
    assert_false(is_prime(0)) # 実行される。パスする。
    assert_false(is_prime(1)) # 実行される。失敗する。
    assert_true(is_prime(2))  # 実行されない。
    assert_false(is_prime(4)) # 実行されない。

is_prime(1)以降が実行されないため、is_prime(1)のパターンだけが失敗するようになったのか、他のパターンも一緒に失敗するようになったかがわかりません。

問題を解決する時は、まず、どのようなときに発生するのかを見極める、つまり、原因を見極める必要があります。そのとき、問題が発生するときの情報を多く得られると、原因を見極めるために役立ちます。そのため、独立したパターンは独立して実行されるようにしておく方がよいのです。

しばらくテストを書いたり読んだりしていると、実は、前者の書き方には上記の理由以上に大事なことがあることがわかります。それは、テストする内容に名前をつけていることです。プログラミングは名前をつける作業である、と言っても過言ではありませんが、それについてはまたいつか書く機会があるといいですね。

データ駆動テスト後

だいぶ前置きが長くなりましたが、データ駆動テスト機能を使う場合は以下のように書きます。

test_prime.py:

1
2
3
4
5
6
7
8
9
10
11
import pikzie

@pikzie.data("small", 2)
def test_true(number):
    assert_true(is_prime(number))

@pikzie.data("zero", 0)
@pikzie.data("unit", 1)
@pikzie.data("square", 4)
def test_false(number):
    assert_false(is_prime(number))

@pikzie.data()でテスト(ここではtest_truetest_false)にデータの名前とデータを登録します。データを登録するとあとはPikzieがデータを引数としてテストを実行します。

それぞれのテストデータは独立しているので、1つのテストデータでテストが失敗しても、他のテストデータは影響を受けません。あるテストデータに対してテストが失敗したかどうかに関わらず、すべてのテストが実行されます。つまり、データ駆動テストを使用していない2つの例のうち、前者と同じ挙動になるということです。

is_prime(1)が失敗する場合は、以下のようになります。

1
2
3
4
5
6
7
8
9
@pikzie.data("small", 2) # 実行される。パスする。
def test_true(number):
    assert_true(is_prime(number))

@pikzie.data("zero", 0) # 実行される。パスする。
@pikzie.data("unit", 1) # 実行される。失敗する。
@pikzie.data("square", 4) # 実行される。パスする。
def test_false(number):
    assert_false(is_prime(number))

データ駆動テスト機能を使うと、テストの内容には「どのようにテストしたいか」という本質的な部分だけが残ります。また、テストパターンを追加するときは、パラメータ化したテストデータの方に注目することができます。これにより、メンテナンスのしやすいテストを書くことができます。

まとめ

Pikzie 0.9.5から0.9.7の間で追加された大きな機能であるデータ駆動テスト機能について紹介しました。

いろいろなパターンがあるテストでデータ駆動テスト機能を使ってみてはいかがでしょうか。

2010-05-25

«前の記事: git-utils 0.0.1リリース 最新記事 次の記事: 日本Ruby会議2010スポンサーと発表・企画のお知らせ»
タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|