テストを学ぼう (1) ! ~ユニットテストについて~
ユニットテストってなんでするの?
書いたコードがちゃんと動くか不安だから。
テストを書いておくと安心を得ることができます。安心大事。
また、大胆にリファクタリングだってできちゃう。
以下の考え方はユニットテストが基盤
- 継続的テスト
- テスト駆動開発
- ビヘイビア駆動開発
継続的テストとは
テストを早い段階から(できれば自動的に)回すことが大事。理由は、手戻り、リグレッション(テストに失敗→修正→新たな問題が発生)が発生するからです。
ユニットテストは最小クラスの部品などを対象とするため、早い段階から回すことができます。また、自動化がしやすく、ローコストで繰り返し行うことができます。
こうすることで、修正による影響がすぐにフィードバックされ、安心してリリースができる。
テスト駆動開発とは
プロダクションコードを書く前にテストを書く方法。テストファースト。目的が明確になるため、目的にあったすっきりとしたコードがかける。
参考:@IT:特集 「テスト駆動開発」はプログラマのストレスを軽減するか?
ビヘイビア駆動開発とは
仕様を起点とした開発手法。テストファーストに対してスペックファーストという。
pythonでは「behave」という振舞駆動開発ツールがある。
参考: 振る舞い駆動開発入門 ビヘイビア駆動開発 - Wikipedia Welcome to behave! — behave 1.2.5 documentation ビヘイビア駆動開発ツール
ユニットテストを書いてみよう
pythonでunittestを用いるものとする
参考: 26.4. unittest — ユニットテストフレームワーク — Python 3.6.1 ドキュメント Pythonでエラーが発生することをテストする - Misc Notes
以下のプロダクトコードとテストコードを同じフォルダに配置する
プロダクトコード
数値微分をしてみる
以下をnumerical_diff.pyとして保存
# -*- coding:utf-8 -*- # 2次関数の数値微分を行うクラス class Diff: # 2次関数 def f(self,x): y = x**2 return y # 数値微分 def numerical_diff(self,f,x,dx): if dx == 0: raise ValueError('division by zero') else: x_diff = (f(x+dx)-f(x-dx))/(2*dx) return x_diff if __name__ == '__main__': diff = Diff() print diff.numerical_diff(diff.f,3,0.001)
テストコード
以下をtest_numerical_diff.pyとして保存
# -*- coding:utf-8 -*- import unittest, numerical_diff class TestDiff(unittest.TestCase): # 前処理 def setUp(self): self.diff = numerical_diff.Diff() # 後片付け def tearDowm(self): pass # 3の2乗のテスト def test_func1(self): self.assertEqual(self.diff.f(3),9) # 4の2乗のテスト def test_func2(self): self.assertEqual(self.diff.f(4),16) # 数値微分ができているかのテスト def test_numerical_diff(self): self.assertAlmostEqual(self.diff.numerical_diff(self.diff.f,3,0.001),6.0, delta=1e-8) self.assertEqual(round(self.diff.numerical_diff(self.diff.f,3,0.001)),6.0) # 良くない例 # 0で割られたときの例外のテスト def test_numerical_diff_zero_error(self): with self.assertRaises(ValueError) as cm: self.diff.numerical_diff(self.diff.f,3,0.0) exception = cm.exception self.assertEqual(exception.message, 'division by zero') if __name__ == "__main__": unittest.main()
参考:2. 組み込み関数 — Python 3.6.1 ドキュメント
実行方法
以下を上記フォルダ内で実行
python -m unittest test_numerical_diff
もしくはターミナルで
$ ipython $ run test_numerical_diff.py
実行結果
.... ---------------------------------------------------------------------- Ran 4 tests in 0.000s OK
今後勉強したいツール
nose