[Python] ユニットテストをPythonで書く
こんにちは、@yoheiMuneです。
皆様はUnitテスト書かれていますかー?僕は自分のアプリケーションでunitテストを書くようにしています。今日はPythonでのUnitテストの書き方をブログに書きたいと思います。
 
さてUnitテストに関する所感は以上にするとして、単体テストに着いてPythonでも幾つかのライブラリが存在します。けど、標準ライブラリの
http://docs.python.jp/3/library/unittest.html
それではさっそく使ってみたいと思います。
実行は以下のように行います。
また途中に出てきた
http://docs.python.jp/3/library/unittest.html#unittest.TestCase.assertEqual
基本的には上記のコードで十分にテストができます。必要なだけテストを書いて、プログラム本体の品質を担保します。
最後になりますが本ブログでは、Python・フロントエンド・開発関連・Swift・Linux・Java・機械学習など雑多に情報発信をしていきます。自分の第2の脳にすべく、情報をブログに貯めています。気になった方は、本ブログのRSSやTwitterをフォローして頂けると幸いです ^ ^。
最後までご覧頂きましてありがとうございました!
皆様はUnitテスト書かれていますかー?僕は自分のアプリケーションでunitテストを書くようにしています。今日はPythonでのUnitテストの書き方をブログに書きたいと思います。
 
目次
単体テストを書く理由
僕が単体テストを書く理由は、別に誰からか強制されているわけではなく、自分のために書きます。ユニットテストを書くことで以下のメリットがあるなぁと感じています。- コーディングしながら同時にテストもできて品質を確保しやすい
- テストしやすいメソッド設計になって、今後のメンテナンスをしやすい(例えば将来仕様変更があった場合にも、メソッドを修正してテストも修正すれば、最低限品質を担保できる
- 細かくテストができてテストバリエーションを確保でき、品質に繋がる。例えばHTTP〜アプリ〜DBを通してテストする場合には、どうしても細かい部分はテストしづらい)
- 新しいライブラリなど使う場合に、いろいろと実験できて(機能検証に使えて)嬉しい。必要に応じて細かい挙動なども確認できる
さてUnitテストに関する所感は以上にするとして、単体テストに着いてPythonでも幾つかのライブラリが存在します。けど、標準ライブラリの
unittestが強力でそれで十分かなーと思うので、今日はそれをブログに書きたいと思います。unittestモジュールについて
unittestモジュールはPythonの標準ライブラリで、JUnitライクなテストフレームワークです(JUnitっぽいフレームワークは、JSやPHPなど様々な言語で存在します)。強力なライブラリで必要なことは大体ありますので、必要に応じて以下のリファレンスをご確認ください。http://docs.python.jp/3/library/unittest.html
それではさっそく使ってみたいと思います。
Unitテストの準備
準備は非常に簡単で、以下のインポート文を書くだけです(標準ライブラリなのでpipする必要もありません)。import unittest
単体テストを書いてみる
それでは早速単体テストを書いて見たいと思います。unittest.TestCaseクラスを継承したテスト用のクラスを作成します。
# test.py
# unittest.TestCaseの子クラスを作成します
class MyTest(unittest.TestCase):
    # メソッド名は必ず「test」をプレフィックスに付けます
    def test_do_something(self):
        # 検証を行います
        one = 1
        self.assertEqual(one, 1, "one is 1")
これでテストコードは完成です。簡単ですね!実行は以下のように行います。
$ python -m unittest test.pyまたは、
test.pyに起動処理を実装して、それを使うこともできます。
# test.py
if __name__ == "__main__":
    unittest.main()
$ python test.pyこっちの方がコマンド実行が楽なので便利ですねー。
また途中に出てきた
assertEqualについては検証を行うメソッドですが、他にもassertTrueなど色々とあります。詳細は以下をご確認ください。http://docs.python.jp/3/library/unittest.html#unittest.TestCase.assertEqual
基本的には上記のコードで十分にテストができます。必要なだけテストを書いて、プログラム本体の品質を担保します。
setUpとtearDown
setUpメソッドを用いることでテスト前に処理を実行できて、tearDownメソッドを用いることでテスト後に処理を実行することができます。
class MyTest(unittest.TestCase):
    # 各テスト前に呼び出される
    # DBのセットアップやテストデータの準備などを行う
    def setUp(self):
        print("setUp is called.")
    # 各テスト後に呼び出される
    # テストの後処理(成果物の削除)やDB処理の後処理などを行う
    def tearDown(self):
        print("tearDown is called.")
    def test_do_something(self):
        print("test_do_something")
        one = 1
        self.assertEqual(one, 1, "one is 1")
    def test_do_otherthing(self):
        print("test_do_otherthing")
        two = 2
        self.assertTrue(two == 2, "two is 2")
if __name__ == "__main__":
    unittest.main()
これを実行すると以下のように出力され、それぞれがテスト前後に実行されていることがわかります。$ python test.py setUp is called. test_do_otherthing tearDown is called. .setUp is called. test_do_something tearDown is called. ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK各メソッドで共通的な前/後処理がある場合には便利です。
setUpClassとtearDownClass
直前の内容に似ていますが、setUpClassとtearDownClassは、テストクラスの最初と最後にそれぞれ呼び出されます。
class MyTest(unittest.TestCase):
    # テスト開始時に1回だけ呼び出される
    # クラスメソッドとして定義する
    @classmethod
    def setUpClass(cls):
        print("setUpClass is called.")
    # テスト終了時に1回だけ呼び出される
    # クラスメソッドとして定義する
    @classmethod
    def tearDownClass(cls):
        print("tearDownClass is called.")
    def test_do_something(self):
        print("test_do_something")
        one = 1
        self.assertEqual(one, 1, "one is 1")
    def test_do_otherthing(self):
        print("test_do_otherthing")
        two = 2
        self.assertTrue(two == 2, "two is 2")
if __name__ == "__main__":
    unittest.main()
$ python test.py setUpClass is called. test_do_otherthing .test_do_something .tearDownClass is called. ---------------------------------------------------------------------- Ran 2 tests in 0.000s OKこちらも全テストで共通の前/後処理(で且つテスト中に不変なこと)があれば、ここで記述すると便利です。
テストのスキップ
unittest.skipデコレーターをメソッドやクラスにつけることで、そのテストをスキップすることができます。
# メソッドをスキップする場合
# カッコ内はスキップ理由などを書く
@unittest.skip("今は動かしたくない。そう自分のエゴだけどね。")
def test_do_thing_for_skip(self):
    print("skip this method, so it is never called.")
# クラスにも付与することができます
# テストスイートなどで使うときに重宝します
@unittest.skip("ちょっと時間がかかるから今はスキップ")
class MyTest(unittest.TestCase):
様々なテストを書いた場合に、一部のテストのみを実行したくてスキップする時が時々あります。最後に
今日はPythonのユニットテストでした。今回は書けなかったけど今後にテストスイートについても書きたいと思います(業務ではよく使うので)。テストを書いて品質確保をぜひぜひやっていきたいところです(手動テストは非常に辛いから減らしたい・・・)。最後になりますが本ブログでは、Python・フロントエンド・開発関連・Swift・Linux・Java・機械学習など雑多に情報発信をしていきます。自分の第2の脳にすべく、情報をブログに貯めています。気になった方は、本ブログのRSSやTwitterをフォローして頂けると幸いです ^ ^。
最後までご覧頂きましてありがとうございました!
 
  
