ããã¯ããªã«ãããããŠæžãããã®ïŒ
Pythonãå匷ããã«ããã£ãŠããã¹ãã³ãŒããŸããã«ã€ããŠå°ãæŒãããŠãããæ¹ãããããªããšæããŸããŠã
Pythonã«ã¯ãããã€ããã¹ãããµããŒãããã©ã€ãã©ãªãããŒã«ãããããã§ãã
コードのテスト — The Hitchhiker's Guide to Python
Testing Your Code — The Hitchhiker's Guide to Python
ä»åã¯åºæ¬ã§ãããunittestã䜿ã£ãŠã¿ãããšã«ããŸããã
unittest
Pythonæšæºã«å«ãŸãããJUnitã«è§Šçºããããã¹ãã£ã³ã°ãã¬ãŒã ã¯ãŒã¯ã§ãã
26.4. unittest --- ユニットテストフレームワーク — Python 3.6.9 ドキュメント
unittest ãŠããããã¹ããã¬ãŒã ã¯ãŒã¯ã¯å ã JUnit ã«è§Šçºããããã®ã§ã ä»ã®èšèªã®äž»èŠãªãŠããããã¹ããã¬ãŒã ã¯ãŒã¯ãšåããããªæãã§ãã ãã¹ãã®èªååããã¹ãçšã®ã»ããã¢ãããã·ã£ããããŠã³ã®ã³ãŒãã®å ±æããã¹ãã®ã³ã¬ã¯ã·ã§ã³åããããŠå ±åãã¬ãŒã ã¯ãŒã¯ããã®ãã¹ãã®ç¬ç«æ§ããµããŒãããŠããŸãã
ãã¹ãã±ãŒã¹ã®äœæã®ããã®ã¯ã©ã¹ãã¢ãµãŒã·ã§ã³ãå«ã¿ãã©ã³ããŒãæäŸããŸãã
ã¢ãµãŒã·ã§ã³ã«ã€ããŠã¯ããã¡ãã
ã¢ãµãŒãã¡ãœããäžèŠ§
assertAlmostEqual
â»assertAlmostEqualã¡ãœããã®ãªãã¡ã¬ã³ã¹ã®äžã«ãäžèŠ§ããããŸã
å®è¡ã«ã€ããŠã¯ãunittestãã³ãã³ãã©ã€ã³ããã¢ãžã¥ãŒã«æå®ã§å®è¡ããããšã§è¡ããŸãã
ã³ãã³ãã©ã€ã³ã€ã³ã¿ãŒãã§ã€ã¹
ç¹å®ã®ãã£ã¬ã¯ããªã®é äžã®ãã¹ãã³ãŒããæ€åºããããã¹ããã£ã¹ã«ããªãå¯èœã§ãã
ãšããã§ãã³ãŒãã®ãã¹ãã§ã玹ä»ãããŠããŸãããpytestãšãããã®ãæŒãããŠãããæ¹ããããããªã®ã§ããã¡ãããã®ãã¡ã
pytest: helps you write better programs — pytest documentation
ç°å¢
ä»åã®ç°å¢ã¯ããã¡ãã§ãã
$ python3 -V Python 3.6.8
ãé¡ãšãããžã§ã¯ãæ§æ
ãã¹ã察象ã®ã³ãŒãïŒã¢ããªã±ãŒã·ã§ã³ã³ãŒãïŒãšããã¹ãã³ãŒããåããã£ã¬ã¯ããªã«é
眮ããŠããµã³ãã«çã«åãããŠã¿ãŠã
ããã®ã§ããããã£ãããªãå®éã«äœ¿ãæã®æ§æãæèããŠã¿ãããªããšæããŸãã
ãã¹ãã³ãŒããé 眮ãããã£ã¬ã¯ããªæ§æã¯ãpytestã®ããã¥ã¡ã³ããåèã«ã
Choosing a test layout / import rules
ãã¹ãã³ãŒããã¢ããªã±ãŒã·ã§ã³ã³ãŒãã®å€ã«çœ®ãã¹ã¿ã€ã«ãš
Tests outside application code
ãã¹ãã³ãŒããã¢ããªã±ãŒã·ã§ã³ã³ãŒãã®äžã«çœ®ãã¹ã¿ã€ã«ãããããã§ãã
Tests as part of application code
ä»åã¯ããã¹ãã³ãŒããã¢ããªã±ãŒã·ã§ã³ã³ãŒãã®å€ã«çœ®ãããšã«ããŸããã
ãããªãã£ã¬ã¯ããªæ§æã«ããŸãã
sample ## â ã¢ããªã±ãŒã·ã§ã³ã³ãŒãã眮ã tests ## â ãã¹ãã³ãŒãã眮ã
ãã¹ãã³ãŒãã®ãã£ã¹ã«ããªãè©Šãããã«ãã¢ããªã±ãŒã·ã§ã³ã³ãŒãã2ã€ã®ãã¡ã€ã«ã§äœæãã察å¿ãããã¹ãã2ã€çšæããæ§æã«
ããããšæããŸãã
ãã¹ããäœæããŠãå®è¡ããŠã¿ã
ãŸãæåã«ãã¢ããªã±ãŒã·ã§ã³ã³ãŒããæžããŸãã sample/calc.py
class Calc: def add(self, x, y): return x + y def minus(self, x, y): return x - y def multiply(self, x, y): return x * y def divide(self, x, y): return x / y
ããã«å¯Ÿå¿ããããã¹ãã³ãŒããæžããŸãããã
unittestã䜿ãå Žåããã¹ãã¯TestCaseã¯ã©ã¹ã®ãµãã¯ã©ã¹ãšããŠäœæããããã§ãã
ãŸãããã¹ããè¡ãã¡ãœããåã¯ããtestãã§å§ãŸãå¿ èŠãããããã§ãã
ãã¹ãã±ãŒã¹ã¯ã unittest.TestCase ã®ãµãã¯ã©ã¹ãšããŠäœæããŸããã¡ãœããåã test ã§å§ãŸãäžã€ã®ã¡ãœããããã¹ãã§ãããã¹ãã©ã³ããŒã¯ãã®åœåèŠçŽã«ãã£ãŠãã¹ããè¡ãã¡ãœãããæ€çŽ¢ããŸãã
ã¢ãµãŒã·ã§ã³ã¯ãunittestïŒãšãããTestCaseã¯ã©ã¹ïŒãæäŸããã¡ãœããã䜿çšããŠè¡ããŸãã
ã§ãäœæããã®ããã¡ãã
tests/test_calc.py
import unittest from sample.calc import Calc class CalcTestCase(unittest.TestCase): def setUp(self): print("setUp!!") def tearDown(self): print("tearDown!!") def test_add(self): sut = Calc() self.assertEqual(sut.add(1, 3), 4) def test_minus(self): sut = Calc() self.assertEqual(sut.minus(5, 3), 2) def test_multiply(self): sut = Calc() self.assertEqual(sut.multiply(2, 3), 6) def test_divide(self): sut = Calc() self.assertEqual(sut.divide(10, 2), 5) def foo(self): print("foo!!")
ããã£ãšããtestãã§å§ãŸããªãã¡ãœãããå«ããŠãããŸãã
ãã¹ãã¡ãœããããšã«å®è¡ããsetUpãtearDownãæžããŠã¿ãŸãããã¯ã©ã¹åäœã®setUpClassãtearDownClassãªã©ããããããªã®ã§ã
ããã¥ã¡ã³ããåç
§ãããšããã§ãããã
ã¯ã©ã¹ãšã¢ãžã¥ãŒã«ã®ãã£ã¯ã¹ãã£
ãã¹ããå®è¡ããŠã¿ãŸãã
$ python3 -m unittest tests.test_calc setUp!! tearDown!! .setUp!! tearDown!! .setUp!! tearDown!! .setUp!! tearDown!! . ---------------------------------------------------------------------- Ran 4 tests in 0.001s OK
setUpãtearDownãããã¹ãã¡ãœããããšã«åããŠãããããªæããããŸãã
ãã詳现ãããããªãã®ã§ã-vããä»ããŠã¿ãŸãã
$ python3 -m unittest tests.test_calc -v test_add (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok test_divide (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok test_minus (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok test_multiply (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok ---------------------------------------------------------------------- Ran 4 tests in 0.000s OK
ãªãã»ã©ãããã ãšå®è¡ããããã¹ãã¡ãœãããããããŸããã
以äžã®ã¡ãœããã察象ã«å«ãŸããŠããªãããšã確èªã§ããŸããã
def foo(self): print("foo!!")
ãŸãããã¹ãã«å€±æãããããªã³ãŒãã«ãªã£ãŠããå Žåã¯ããããªè¡šç€ºã«ãªããŸãã
====================================================================== FAIL: test_add (tests.test_calc.CalcTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/path/to/tests/test_calc.py", line 14, in test_add self.assertEqual(sut.add(1, 3), 5) AssertionError: 4 != 5
ããšããã²ãšã€ãã¢ããªã±ãŒã·ã§ã³ã³ãŒããè¿œå ããŠ
sample/message.py
class Decorator: def decorate(self, message, character): return "{0}{1}{2}".format(character, message, character)
ãã¹ãã足ããŠãããŸãããã
tests/test_message.py
import unittest from sample.message import Decorator class DecoratorTestCase(unittest.TestCase): def test_decorate(self): sut = Decorator() self.assertEqual(sut.decorate("Hello World!!", "***"), "***Hello World!!***")
確èªã
$ python3 -m unittest tests.test_message -v test_decorate (tests.test_message.DecoratorTestCase) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.000s OK
ãªãããã¹ã察象ãè€æ°æå®ããŠå®è¡ããããšãã§ããŸãã
$ python3 -m unittest tests.test_calc tests.test_message -v test_add (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok test_divide (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok test_minus (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok test_multiply (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok test_decorate (tests.test_message.DecoratorTestCase) ... ok ---------------------------------------------------------------------- Ran 5 tests in 0.001s OK
unittest#main
ããã¥ã¡ã³ãã®ä»¥äžã®éšåã«ãæžããŠããã®ã§ããã
åºæ¬çãªäœ¿ãæ¹ã ãšãunittest#mainãåŒã³åºãããã«ããã¹ãã³ãŒãã«æžãããã§ãã
if __name__ == '__main__': unittest.main()
ã§ãPythonã³ãã³ãã§çŽæ¥å®è¡ããããšã
$ python3 test_example.py
ããã§ãè¯ãã®ã§ãããä»åã®ããã«ã¢ããªã±ãŒã·ã§ã³ã³ãŒããšãã¹ãã³ãŒããå¥ã
ã«ããæ¹æ³ã ãšãã¢ãžã¥ãŒã«ã®ãã¹è§£æ±ºã§
å°ã£ãããšã«ãªã£ãã®ã§ãä»åã¯ãã¹âŠã
ãã¹ããã£ã¹ã«ããªãè¡ã
ãããŸã§ã¯ããã¹ãã³ãŒããã²ãšã€ã²ãšã€æå®ããŠå®è¡ããŠããŸãããããã¹ããã£ã¹ã«ããªã䜿ããšãã¹ãã³ãŒããèŠã€ããŠ
ãããããã§ãã
ã·ã³ãã«ãªå®è¡æ¹æ³ã¯ã以äžã ãšãã
$ python3 -m unittest ### ãŸã㯠$ python3 -m unittest discover
è©ŠããŠã¿ãŸãã
$ python3 -m unittest ---------------------------------------------------------------------- Ran 0 tests in 0.000s OK
âŠãã¹ããå®è¡ãããªãã£ãããã§ãã
ãããã§ãTestLoader#discoverã®èª¬æãèªãã§ã¿ãŸãã
æå®ãããéå§ãã£ã¬ã¯ããªãããµããã£ã¬ã¯ããªã«ååž°ããããšã§ãã¹ãŠã®ãã¹ãã¢ãžã¥ãŒã«ãæ€çŽ¢ããããããå«ã TestSuite ãªããžã§ã¯ããè¿ããŸããpattern ã«ããããããã¹ããã¡ã€ã«ã ããããŒãã®å¯Ÿè±¡ã«ãªããŸãã
ã¢ãžã¥ãŒã«ã«ã€ããŠãããã¡ãã£ãšèª¿ã¹ãŠã¿ãŸãã
ãããã£ã¬ã¯ããªããããã±ãŒãžãå ¥ã£ããã£ã¬ã¯ããªãšããŠPython ã«æ±ãããã«ã¯ããã¡ã€ã« __init__.py ãå¿ èŠã§ãã
ã©ãããã__init__.pyãå¿ èŠãªé°å²æ°ããããŸãã
äœæã
$ touch tests/__init__.py
å床ãå®è¡ã
$ python3 -m unittest setUp!! tearDown!! .setUp!! tearDown!! .setUp!! tearDown!! .setUp!! tearDown!! .. ---------------------------------------------------------------------- Ran 5 tests in 0.000s OK
ä»åºŠã¯åããŸãããã
ã-vããªãã·ã§ã³ãæå®ããŠã¿ãŸãããã
$ python3 -m unittest -v test_add (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok test_divide (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok test_minus (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok test_multiply (tests.test_calc.CalcTestCase) ... setUp!! tearDown!! ok test_decorate (tests.test_message.DecoratorTestCase) ... ok ---------------------------------------------------------------------- Ran 5 tests in 0.001s OK
ãŸãããã£ã¹ã«ããªãéå§ãããã£ã¬ã¯ããªãã-sããªãã·ã§ã³ã§æå®ãããããã¹ããæžããããã¡ã€ã«åã®ãã¿ãŒã³ãã-pãã§
æå®ãããã§ããŸããããããã䜿ãå Žåã¯ãdiscoverããµãã³ãã³ãã®æå®ãå¿
é ã«ãªããŸãã
ãdiscoverããµãã³ãã³ãã®æå®ãªãã§ãã-pããªãã·ã§ã³ãæå®ãããšãšã©ãŒã«ãªããŸãã
$ python3 -m unittest -p 'test_*.py' usage: python3 -m unittest [-h] [-v] [-q] [--locals] [-f] [-c] [-b] [tests [tests ...]] python3 -m unittest: error: unrecognized arguments: -p
ãdiscoverããµãã³ãã³ããæå®ãããšãåäœããŸãã
$ python3 -m unittest discover -p 'test_*.py' setUp!! tearDown!! .setUp!! tearDown!! .setUp!! tearDown!! .setUp!! tearDown!! .. ---------------------------------------------------------------------- Ran 5 tests in 0.000s OK
ãŸãšã
Pythonã®æšæºãã¹ãã©ã€ãã©ãªã§ããunittestããå®è¡æ¹æ³ã®ç¹ããã¡ãã£ãšèŠãŠã¿ãŸããã
ã¢ãµãŒã·ã§ã³ãããã®ä»ã®æ©èœã«ã€ããŠã¯ããŸãèŠããŠããŸãããããšããããåæ©çãªäœ¿ãæ¹ãšããŠã¯ããã£ãæãããªãšã