さて、結局、単体の品質が高くすることがシステム全体の品質を高くできるというのは間違いのないことなのです。
幸い、私はJavaから入ってjUnitを使ったテストファーストを習慣化できたことで、質の高いプログラムを書けるようになったと思っております。
ということで、最近よく使うPythonの単体テストフレームワークについて学んでいきます。
unittest
The unittest unit testing framework was originally inspired by JUnit and has a similar flavor as major unit testing frameworks in other languages.
「unittest」単体テストフレームワークは、jUnitに影響を受けてて、他の言語のメジャーな単体テストフレームワークと似たような感じです、と。
しかもデフォルトで含まれているので、pip installなんかもする必要がありません。
サンプルである
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
もそのまま動いちゃうし、jUnitやってた人なら楽勝でしょう。
import unittest
書いて、
class TestStringMethods(unittest.TestCase):
unittest.TestCaseを継承して
def test_xxxx(self):
self.assertEqual("actual", "expected")
関数でテストコードを書くだけ。
あ、
if __name__ == '__main__':
unittest.main()
最後にこれを書いておく必要はありそう。
実行サンプルは、
$ python Downloads/ab.py ..F FAIL: test_upper (main.TestStringMethods) Traceback (most recent call last): File "Downloads/ab.py", line 6, in test_upper self.assertEqual('foo'.upper(), 'FOOx') AssertionError: 'FOO' != 'FOOx' Ran 3 tests in 0.000s FAILED (failures=1)
という感じ。
pytest
The pytest framework makes it easy to write small tests, yet scales to support complex functional testing for applications and libraries.
「pytest」フレームワークを利用することで、小さなテストを書いやすくなるだけでなく、アプリケーションやライブラリの複雑な機能テストをサポートするくらいスケールできる。
サンプルは非常にシンプル。
※あえてエラーになるようなサンプル。
# content of test_sample.py
def inc(x):
return x + 1
def test_answer():
assert inc(3) == 5
複数テストをしたい場合は
# content of test_class.py
class TestClass:
def test_one(self):
x = "this"
assert "h" in x
def test_two(self):
x = "hello"
assert hasattr(x, "check")
TestClassに複数の関数を定義してあげるだけ。
実行サンプルは
$ pytest pytest_ab.py ========================== test session starts ========================== platform darwin -- Python 3.8.2, pytest-6.2.1, py-1.10.0, pluggy-0.13.1 rootdir: /xxxx/xxxxx collected 2 items pytest_ab.py .F [100%] =============================== FAILURES ================================ ______________ TestClass.test_two _______________ self =def test_two(self): x = "hello"
assert hasattr(x, "check")
E AssertionError: assert False E + where False = hasattr('hello', 'check') pytest_ab.py:9: AssertionError ======================== short test summary info ======================== FAILED pytest_ab.py::TestClass::test_two - AssertionError: a… ====================== 1 failed, 1 passed in 0.04s ======================
という感じで、unittestより情報量が多い。
まとめ
unittestはその他の言語でxUnitをやってきた人にとってはとっつきやすいかも。
pytestは3rdパーティだけあって、pytest-convのようなカバレッジ機能を追加したり、機能テストまでできるところが嬉しいところなのかな。