1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

記事投稿キャンペーン 「2024年!初アウトプットをしよう」

ユニットテストするならフレームワーク使おう (Python unittest)

Posted at

※ 注意

これは「ユニットテストはこういうことを書くのがいいよ!」という話ではありません。「フル自作より、フレームワーク使った方が良いよ」という話です。

良いユニットテストのやり方については、別の解説を探してください。

背景

(恥ずかしながら、真面目にユニットテストをするようになったのは割と最近のお話。)

テストの習慣化を始めたそのときは、テストフレームワークという言葉は聞いたことあったが、まともに向き合っていなかった。

で、あるとき「いい加減フレームワークの一つくらい触れておこうか・・・」と思い、とりあえず Python 標準のユニットテストフレームワーク unittest を使ってみた。

すると、これまで書いていたテストコードより、明らかに書くコード量が減ったではありませんか。なぜ今まで向き合わなかったのか・・・。

というわけで、その感動そのままに、本記事執筆に至りました。

ユニットテストとは (軽く)

単体テストとも。

単体とは、例えば自作関数 1つとか、プログラムが機能するレベルとして最低規模と考えればヨシ。

テストとは、試験、つまりそのプログラムが想定 (設計・仕様) 通りに動くかどうかチェックすること。

要するに、プログラムの小規模パーツ単位でのチェック。より詳しいことは解説がたくさんあるのでカット。

ユニットテストコード例

足し算と引き算のテストをするとします。ここで、引き算のテストには、あえて誤りを入れています。

test_code_original.py
def expect_equal(expected, actual):
  if expected == actual:
    print("--- OK")
  else:
    print("--- NG")
    print(f"Expected: {expected}")
    print(f"Actual  : {actual}")


def test_add():
  print("-- test_add")
  expected = 3
  actual = 1 + 2
  expect_equal(expected, actual)

def test_sub():
  print("-- test_sub")
  expected = 2
  actual = 5 - 2 # 何か不具合があったとする
  expect_equal(expected, actual)


if __name__ == "__main__":
  test_add()
  test_sub()
python3 test_code_original.py
-- test_add
--- OK
-- test_sub
--- NG
Expected: 2
Actual  : 3

unittest 使用で書き直すと

全く同じテストを、今度は unittest 使用で書いてみます。

test_code_unittest.py
import unittest

class test_add_sub(unittest.TestCase):
  def test_add(self):
    expected = 3
    actual = 1 + 2
    self.assertEqual(expected, actual)

  def test_sub(self):
    expected = 2
    actual = 5 - 2  # 何か不具合があったとする
    self.assertEqual(expected, actual)


if __name__ == "__main__":
  unittest.main()
python3 test_code_unittest.py
.F
======================================================================
FAIL: test_sub (__main__.test_add_sub)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<path>/test_code.py", line 12, in test_sub
    self.assertEqual(expected, actual)
AssertionError: 2 != 3

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)

-v オプションを付けると、実行中テスト名を詳しく出してくれます。

python3 test_code_unittest.py -v
test_add (__main__.test_add_sub) ... ok
test_sub (__main__.test_add_sub) ... FAIL

======================================================================
<以降同じ>

テストフレームワークのここが良い

上 2つのコードとテスト結果出力を比較すると、unittest で以下の恩恵が得られると言えそうです。

  • 実行中テスト名を自分で出力しなくてよい
  • テスト結果を自分で出力しなくてよい
  • テスト関数の呼び出しを書かなくてよい
    • unittest.main() だけで OK
    • テスト関数の定義を書く・消すだけ
  • 失敗したテストを詳細に出力してくれる
    • テスト名、結果値の違い、該当の行番号

加えて unittest は Python 標準なので、追加の準備が不要という利点もあります。

ここでは Python の unittest を例にしましたが、cpputest など他のフレームワークも、上のような特徴を持っていることでしょう。

まとめ

ユニットテストフレームワークを導入すると、面倒なコードを書くことなく、テストをサクッと実装できて良い。

「結果出力書くの面倒でテスト書く気起きん」というような人が居たら、早急にフレームワーク導入を勧めましょう。

あと、テストはやるべきというのは言わずもがな。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?