Pythonプログラミング 憧れのテストファースト

 今日も見に来てくださって、ありがとうございます。石川さんです。

 テストファーストのコンセプトを初めて聞いたとき、めっちゃステキなアイディアやん、実現できたらどれだけしあわせなひとが増えることでしょう、と、思っていたのを思い出しました。何度かチュートリアルを経験して、すっかり忘れ去っていました。

 基本的な考え方は簡単で、

  • テスト用プログラムを追加
  • すべてのテストを実行して、追加したテストのエラーが発生するのを確認する
  • テスト対象のプログラムを修正する
  • すべてのテストを実行して、追加したテストが成功することを確認する
  • リファクタリングして、重複を排除、プログラムをきれいにする

という作業を繰り返してプログラムを育てていくプログラミング方法です。

 メリットがいくつかあって、

  • 実行可能なテストが残るため、変更があった時にも再度そのテストを実行することで、これまでの動作保証ができる。
  • テストを先に考えることで、先に仕様を明確にする必要がでてくる。
  • プログラムがテストをやってくれる。
  • テストプログラムを見ることで、作成されたプログラムの利用方法がわかる。
  • プログラミングを「動作させるためのコーディング作業」と「きれいにするためのコーディング作業」に分離できる。

 テストファーストでやっているプロジェクト、これまで見たことがなかったのですよねぇ。現在は増えてきているのでしょうか。問題点は、既存プロジェクトに途中からその考え方を持ち込むことができない(やりにくい)、と、言ったところでしょうか。経験がないのは、自分でやってみるしかないでしょう、ということで、まずは導入部分をやってみたいと思います。

Pythonでのテストファースト

 Pythonの標準モジュールの中に、テスト用フレームワークのunittestがあります。標準ドキュメントにユニットテストフレームワークの説明がありますので、詳細はここで分かると思います。今回は簡単な利用方法について説明します。

unittestの使い方

 テスト用クラスの作成は、unittest.TestCaseを継承して作成します。作成したテストクラスの中にtest_で始まるメソッドを作成することでテストが追加できます。例えば、こんな感じです。

import unittest

class MyFirstTestCase(unittest.TestCase):
    def test_my_first_test(self):
        self.assertEqual(1, 1)

    def test_my_second_test(self):
        self.assertNotEqual(1, 2)

if __name__ == "__main__":
    unittest.main()

 実行するとこんな結果が出力されます。

..
----------------------------------------------------------------------
Ran 2 tests in 0.005s

OK

 出力結果ですが、最初の「..」の点ひとつがテストメソッド一件を表していて、テストが失敗したときに「E」が出力されます。失敗するテストケースを追加してみます。

    def test_my_third_test(self):
        self.assertFalse(True)

 結果はこんな感じの出力になります。

..F
======================================================================
FAIL: test_my_third_test (__main__.MyFirstTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:/work/tkinter_example/unit_test_example.py", line 18, in test_my_third_test
    self.assertFalse(True)
AssertionError: True is not false

----------------------------------------------------------------------
Ran 3 tests in 0.005s

FAILED (failures=1)

 三つ目に「E」が出力されました。

 各テストを実行する前に必ず実行したい処理がある場合は、setUp()メソッドを追加します。各テストの終了時に必ず処理を実行したい場合は、tearDown()メソッドを追加します。

    def setUp(self):
        print('setUp executed!')

    def tearDown(self):
        print('tearDown executed!')

 実行するとこんな風な出力結果になります。

..FsetUp executed!
tearDown executed!
setUp executed!
tearDown executed!
setUp executed!
tearDown executed!

======================================================================
FAIL: test_my_third_test (__main__.MyFirstTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:/work/tkinter_example/unit_test_example.py", line 24, in test_my_third_test
    self.assertFalse(True)
AssertionError: True is not false

----------------------------------------------------------------------
Ran 3 tests in 0.006s

FAILED (failures=1)

 ちょっと「..F」のすぐ後ろに「setUp」の出力結果が続いて出ているのが気になりますが、ちゃんとテストを実行する前後に実行されているようです。

 テストケースの最初に1回だけ、最後に1回だけ実行するようなメソッドは、それぞれ、setUpClass()とtearDownClass()を追加します。ただし、クラスメソッドとして追加する必要があります。

    @classmethod
    def setUpClass(cls):
        print('setUpClass executed!')

    @classmethod
    def tearDownClass(cls):
        print('tearDownClass executed!')

 実行すると以下のように出力が変わります。

..FsetUpClass executed!
setUp executed!
tearDown executed!
setUp executed!
tearDown executed!
setUp executed!
tearDown executed!
tearDownClass executed!

と、長くなってしまいましたが、おおむねこのような感じでテストケースを作成して、プログラムを作ることになります。

“Pythonプログラミング 憧れのテストファースト” への1件の返信

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


reCaptcha の認証期間が終了しました。ページを再読み込みしてください。