mage     Python Testing Fundamentals            Python Testing Fundamentals               Saturday, July 28, 2012         ...
mage     Python Testing Fundamentals     http://drunkenpython.org/pytestfund.pdf          http://drunkenpython.org/pyohio....
About This Tutorial    •Fundamental    •Python 3.2.3    •Assertion    •Unittest    •Doctest                               ...
Why Test?    “Untested Code is Broken Code”            - Phillip von Weitershausen                                   Progr...
Why Test?   •Tests help you design good code   •Test help you find bugs   •Tests help you document code                    ...
Assert Statements•Assert statements use the assert keyword•Assert statements raise AssertionError•Based on bool test expre...
Assert Statements                         keyword >>> assert 1 == 1                                   ProgrammingPyCamp™  ...
Assert Statements expression >>> assert 1 == 1                                  ProgrammingPyCamp™   Copyright © 2012     ...
Assert Statements >>> assert expression is almost the same as: >>> if not expression: ...      raise AssertionError() >>> ...
Assert Statements >>> assert 1 == 1 >>> assert 1 == 2 Traceback (most recent call last):   File "<stdin>", line 1, in <mod...
Assert Statements•A second optional expression on the assert  statement provides a message for the  AssertionError•This he...
Assert Statements   second expression >>> assert 1 == 2, "Reality check"                                  ProgrammingPyCam...
Assert Statements assert expression1, expression2 is almost the same as: if not expression1:    raise AssertionError(expre...
Assert Statements >>> assert 1 == 2, "Reality check" Traceback (most recent call last):   File "<stdin>", line 1, in <modu...
Assert Statements•Assertions may be sprinkled liberally throughout  your code to check that your code is running as  expec...
Assert Statements bigbiz.py: profit = bottom_line(today) assert profit > 0, "Unacceptable!" projection = growth(tomorrow) ...
Assert Statements•Assertions usually generate unhandled  exceptions which halt your program                               ...
Assert Statements bigbiz.py: def bottom_line(timestamp):     """Compute the profit on date."""                  Text     r...
Assert Statements > python bigbiz.py Traceback (most recent call last):  File "bigbiz.py", line 20, in <module>     assert...
Assert Statements•By using Pythons -i command line switch, you  may interactively inspect what went wrong where  the asser...
Assert Statements > python -i bigbiz.py Traceback (most recent call last):   File "bigbiz.py", line 20, in <module>     as...
Assert Statements•By using Pythons -i command line switch, you  may use also Pythons debugger to see what  went wrong at t...
Assert Statements > python -i bigbiz.py Traceback (most recent call last):   File "bigbiz.py", line 20, in <module>     as...
Assert Statements•Assertions may be turned off by "optimizing"  Python with the -O command line switch                    ...
Assert Statements > python -O >>> assert 1 == 2 >>>                                  ProgrammingPyCamp™   Copyright © 2012...
Assert Statements > python -O bigbiz.py Profit is -1000000.00 USD. Projected profit is -2000000.00 USD. >                 ...
Assert Statements•Its a fine line whether assert statements are  testing or debugging•Assert statements are slightly more s...
Unittest Module•Unittest is "batteries included" in Python•Unittest helps you separate test code from the  code under test...
Unittest Module >>> import unittest >>> dir(unittest) [BaseTestSuite, FunctionTestCase, SkipTest, TestCase, TestLoader, Te...
TestCase Class•unittest.TestCase is a class•You create TestCase subclasses•You add methods whose names start with "test"  ...
TestCase Class•Each test method you supply in your subclass  executes a TestCase supplied method whose  name starts with "...
TestCase Class test_operator.py: """Demonstrate the unittest module."""                              Text import operator ...
TestCase Class test_operator.py: class TestOperator(unittest.TestCase):                              Text     """Test the ...
TestCase Class test_operator.py: def test_add(self):     """Test the add function."""                              Text   ...
TestCase Class test_operator.py: def test_sub(self):     """Test the sub function."""                              Text   ...
TestCase Class test_operator.py: def test_mul(self):     """Test the mul function."""                              Text   ...
TestCase Class test_operator.py: if __name__ == "__main__":                              Text     unittest.main()         ...
main Class•unittest.main is also a class•unittest.main is normally only used within a  script containing test fixtures•When...
main Class > python test_operator.py ... -------------------------------------- Ran 3 tests in 0.001s OK >                ...
TestLoader Class•Notice that nowhere does it appear that your  script has instantiated your TestCase subclass or  execute ...
TestRunner Class•Once the TestLoader instance created by  unittest.main discovers and instantiates the  TestCase in your s...
TestRunner Class   TestCase                                    unittest.main    (superclass)                              ...
main Class test_operator.py: if __name__ == "__main__":                              Text     unittest.main(verbosity=2)  ...
main Class > python     test_operator.py test_add     (__main__.TestOperator) Test the     add function. ... ok test_mul  ...
main Class•Notice that your tests did not run in the same  order in which they were defined•unittest.main loads the test me...
TestCase Class test_operator.py: def test_add(self):     """Test the add function."""                              Text   ...
TestCase Class > python test_operator.py F.. ====================================== FAIL: test_add (__main__.TestOperator)...
TestCase Class test_operator.py: def test_add(self):     """Test the add function."""                              Text   ...
TestCase Class > python test_operator.py E.. ================================================ ERROR: test_add (__main__.Te...
TestResult Class•Running a test results in one of three outcomes:   ★   Success (expected result)   ★   Failure (unexpecte...
TestResult Class•Most of the time you will not need to create your  own TestResult instances•Most of the ways you will run...
TestResult Class > python -m unittest test_operator ... -------------------------------------- Ran 3 tests in 0.000s OK > ...
TestResult Class > python -m unittest       test_operator.TestOperator ... -------------------------------------- Ran 3 te...
TestResult Class > python -m unittest       test_operator.TestOperator.test_add . -------------------------------------- R...
TestResult Class > python -m unittest test_operator.py ... -------------------------------------- Ran 3 tests in 0.000s OK...
TestResult Class > python     -m unittest -v test_operator test_add     (test_operator.TestOperator) Test the     add func...
TestResult Class > python -m unittest -h Usage: python -m unittest [options] [tests] Options:   -h, --help       Show this...
load_tests Protocol > python -m unittest ....... -------------------------------------- Ran 7 tests in 0.000s OK >        ...
load_tests Protocol Alternative Usage: python -m unittest                     discover [options] Options:   -s directory  ...
TestCase Class•Notice that TestCase.assertEqual does not  appear to raise an unhandled AssertionError•The TestRunner insta...
TestCase Class                    Method               Tests If    assertEqual(a, b)           a == b    assertNotEqual(a,...
TestCase Class•You not only need to test if your code produces  expected results, you also need to test if your  code hand...
TestCase Class test_operatorNG.py: def test_add_str(self):    """Test bad args for add."""                              Te...
TestCase Class > python -m unittest test_operatorNG .... -------------------------------------- Ran 4 tests in 0.000s OK >...
TestCase Class                 Method                          Tests If   assertRaises(exception)               exception ...
TestCase Class               Method                       Tests If  assertAlmostEqual(a, b)        round(a-b, 7) == 0  ass...
TestCase Class               Method                        Compares  assertMultiLineEqual(a, b)     Strings  assertSequenc...
TestCase Class•Plus many more! >>> [attr for attr ...   in dir(unittest.TestCase) ...   if attr.startswith(assert)]       ...
TestCase Class >>> help(unittest.TestCase. ...      assertDictContainsSubset) Help on function assertDictContainsSubset in...
TestSuite Class test_operatorNG2.py: """Demonstrate the unittest module."""                             Text import operat...
TestSuite Class test_operatorNG2.py: class TestAdd(unittest.TestCase):                             Text     """Test the ad...
TestSuite Class test_operatorNG2.py: def test_add_int(self):    """Test with ints."""                             Text    ...
TestSuite Class test_operatorNG2.py: def test_add_str(self):    """Test with strs."""                             Text    ...
TestSuite Class test_operatorNG2.py: class TestSub(unittest.TestCase):                             Text     """Test the su...
TestSuite Class test_operatorNG2.py: def test_sub_int(self):    """Test with ints."""                             Text    ...
TestSuite Class test_operatorNG2.py: def test_sub_str(self):    """Test with strs."""                              Text   ...
TestSuite Class test_operatorNG2.py: class TestMul(unittest.TestCase):                             Text     """Test the mu...
TestSuite Class test_operatorNG2.py: def test_mul_int(self):    """Test with ints."""                             Text    ...
TestSuite Class test_operatorNG2.py: def test_mul_str(self):    """Test with strs."""                             Text    ...
TestSuite Class test_operatorNG2.py: str_suite = unittest.TestSuite()                    Text str_suite.addTest(TestAdd("t...
TestSuite Class test_operatorNG2.py: if __name__ == "__main__":                             Text    unittest.main()       ...
TestSuite Class•Objects you have bound in the  test_operatorNG2 namespace:  •TestAdd class  •TestSub class  •TestMul class...
TestSuite Class > python test_operatorNG2.py ...... -------------------------------------- Ran 6 tests in 0.001s OK >     ...
TestSuite Class > python -m unittest             test_operatorNG2.str_suite ... -------------------------------------- Ran...
TestSuite Class > python -m unittest -v           test_operatorNG2.str_suite test_add_str (test_operatorNG2.TestAdd) Test ...
Organizing Tests pyohio-+        bin/python        pycamp-+               __init__.py               setup.py              ...
Organizing Tests > python pycamp/fibonacci.py 100 1 2 3 5 8 13 21 34 55 89 > python >>> from pycamp.fibonacci import fib >...
Organizing Tests > python pycamp/triangular.py 100 1 3 6 10 15 21 28 36 45 55 66 78 91 > python >>> from pycamp.triangular...
Organizing Tests pycamp/tests/test_fibonacci.py: """Tests for the fibonacci module."""                             Text fro...
Organizing Tests pycamp/tests/test_fibonacci.py: class TestFibonacci(unittest.TestCase):                             Text  ...
TestCase Class•TestCase also supplies methods you override•TestCase.setUp() is called before every test  method you supply...
TestCase Class•Your TestCase subclasses, along with all the  test methods you supply, and all the TestCase  supplied metho...
Organizing Tests pycamp/tests/test_fibonacci.py: def setUp(self):    """Test fixture build."""                             ...
Organizing Tests pycamp/tests/test_fibonacci.py: def test_fib_100(self):    """Test fib for numbers < 100."""              ...
Organizing Tests pycamp/tests/test_fibonacci.py: def test_fib_10(self):    """Test fib for numbers < 10."""                ...
Organizing Tests pycamp/tests/test_fibonacci.py: if __name__ == "__main__":                             Text    unittest.ma...
Organizing Tests pycamp/tests/test_triangular.py: """Tests for the triangular module."""                              Text...
Organizing Tests pycamp/tests/test_triangular.py: class TestTriangular(unittest.TestCase):                              Te...
Organizing Tests pycamp/tests/test_triangular.py: def setUp(self):     """Test fixture build."""                          ...
Organizing Tests pycamp/tests/test_triangular.py: def test_tri_100(self):     """Test tri for numbers < 100."""           ...
Organizing Tests pycamp/tests/test_triangular.py: def test_tri_10(self):     """Test tri for numbers < 10."""             ...
Organizing Tests pycamp/tests/test_triangular.py: if __name__ == "__main__":                              Text     unittes...
Organizing Tests > python -m unittest discover       -s pycamp -t . .... -------------------------------------- Ran 4 test...
Organizing Tests pycamp/setup.py: """Setup for pycamp package."""                             Text from setuptools import ...
Organizing Tests pycamp/setup.py: setup(    name="pycamp",    version="1.0", Text    packages=find_packages(),    author="...
Organizing Tests pycamp/setup.py:     description="Testing Fundamentals",     license="PSF",                    Text     k...
Organizing Tests > python pycamp/setup.py test running test ..lots of output omitted for brevity.. -----------------------...
Organizing Tests > python pycamp/setup.py test                                  ProgrammingPyCamp™   Copyright © 2012     ...
Organizing Tests > python pycamp/setup.py install                                  ProgrammingPyCamp™   Copyright © 2012  ...
Organizing Tests > python pycamp/setup.py register                                  ProgrammingPyCamp™   Copyright © 2012 ...
Unittest Module•unittest provides nice separation of tests from  code•One person can write tests, while another writes  co...
Unittest Module•However, it can be difficult to keep tests and  code in sync•Also, writing code to test code can also be mo...
Doctest Module•Informally, even without written tests, you  probably already test your code by simply using  it as it was ...
Doctest Module pyohio-+        bin/python        pycampNG-+               __init__.py               setup.py              ...
Doctest Module pycampNG/fibonacci.py: """A module of functions about non-zero Fibonacci numbers.                           ...
Doctest Module pycampNG/fibonacci.py: def fib(n):    """Return the sequence of non-zero    Fibonacci numbers less than n.  ...
Doctest Module pycampNG/fibonacci.py:    >>> lessThan100 = [1, 2, 3, 5, 8, 13,    ...                              21, 34, ...
Doctest Module pycampNG/triangular.py: """A module of functions about non-zero triangular numbers.                        ...
Doctest Module pycampNG/triangular.py: def tri(n):    """Return the sequence of non-zero    triangular numbers less than n...
Doctest Module pycampNG/triangular.py:    >>> lessThan100 = [1, 3, 6, 10, 15,                              21, 28, 36, 45,...
Doctest Module > python -m doctest pycampNG/fibonacci.py >                                  ProgrammingPyCamp™   Copyright...
Doctest Module > python -m doctest -v                           pycampNG/fibonacci.py Trying:      import fibonacci Expect...
Doctest Module Trying:      lessThan100 = [1, 2, 3, 5, 8, 13,                              21, 34, 55, 89] Expecting nothi...
Doctest Module Trying:      fib(100) == lessThan100 Expecting:      True ok                                    Programming...
Doctest Module Trying:      fib(10) == lessThan100[:5] Expecting:      True ok                                    Programm...
Doctest Module 2 items passed all tests:     1 tests in fibonacci     3 tests in fibonacci.fib 4 tests in 2 items. 4 passe...
Doctest Module > python -m doctest pycampNG/triangular.py >                                  ProgrammingPyCamp™   Copyrigh...
Doctest Module pycampNG/fibonacci.py: if __name__ == __main__:    if sys.argv[1].lower() == test:          import doctest  ...
Doctest Module pycampNG/triangular.py: if __name__ == __main__:    if sys.argv[1].lower() == test:          import doctest...
Doctest Module > python pycampNG/fibonacci.py test > python pycampNG/fibonacci.py 100 1 2 3 5 8 13 21 34 55 89 >          ...
Doctest Module > python pycampNG/triangular.py test > python pycampNG/triangular.py 100 1 3 6 10 15 21 28 36 45 55 66 78 9...
Doctest Module•But what about setuptools.setup?•The test_suite argument of setup triggers  unittest discovery, not doctest...
Doctest Module•The doctest.DocTestSuite() function  searches a module for doctests and converts  them into a unittest.Test...
load_tests Protocol def load_tests(loader,                              tests,                              pattern):     ...
load_tests Protocol                                       unittest.TestLoader def load_tests(loader,                      ...
load_tests Protocol def load_tests(loader,                                       unittest.TestSuite                       ...
load_tests Protocol def load_tests(loader,                              tests,                                       "test...
load_tests Protocol def load_tests(loader,                              tests,                              pattern):     ...
load_tests Protocol pycampNG/tests/test_pycamp.py: import doctest                             Text from pycampNG import fi...
load_tests Protocol pycampNG/tests/test_pycamp.py: def load_tests(loader, tests, pattern):    tests.addTests(          doc...
load_tests Protocol pycampNG/tests/test_pycamp.py: def load_tests(loader, tests, pattern):    tests.addTests(          doc...
load_tests Protocol pycampNG/tests/test_pycamp.py: def load_tests(loader, tests, pattern):     tests.addTests(          do...
load_tests Protocol pycampNG/tests/test_pycamp.py: def load_tests(loader, tests, pattern):    tests.addTests(          doc...
load_tests Protocol pycamp/setup.py: setup(     name="pycampNG",                              Text     ...     test_suite=...
load_tests Protocol > python pycampNG/setup.py test running test ..lots of output omitted for brevity.. ------------------...
Doctest Module Together, the doctest.DocTestSuite() function and the load_tests protocol from the unittest module enable y...
Python Testing Tools Taxonomy                             ProgrammingPyCamp™   Copyright © 2012              Trizpug      ...
Test Driven Development•Doctests enable you to do Test Driven  Development (TDD)•TDD is where you write tests for your cod...
Test Driven Development•When all your tests pass, then you have finished  coding•You can develop your code incrementally,  ...
Test Driven Development•If your code needs more features, then what you  really need is more tests, and code which makes  ...
Test Driven Development                               ProgrammingPyCamp™    Copyright © 2012               Trizpug        ...
Tomorrow 12:15pm in Barbie Tootle                              ProgrammingPyCamp™   Copyright © 2012              Trizpug ...
Thank You                 pycamp@trizpug.org                                      ProgrammingPyCamp™   Copyright © 2012   ...
Upcoming SlideShare
Loading in...5
×

Python Testing Fundamentals

1,928

Published on

Slides from PyOhio, a brief tour of unittest and doctest.

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,928
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
90
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Python Testing Fundamentals

  1. 1. mage Python Testing Fundamentals Python Testing Fundamentals Saturday, July 28, 2012 PyOhio Ohio State University Columbus, OH Chris Calloway University of North Carolina Department of Marine Sciences ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  2. 2. mage Python Testing Fundamentals http://drunkenpython.org/pytestfund.pdf http://drunkenpython.org/pyohio.zip http://drunkenpython.org/pyohio.tgz ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  3. 3. About This Tutorial •Fundamental •Python 3.2.3 •Assertion •Unittest •Doctest ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  4. 4. Why Test? “Untested Code is Broken Code” - Phillip von Weitershausen ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  5. 5. Why Test? •Tests help you design good code •Test help you find bugs •Tests help you document code ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  6. 6. Assert Statements•Assert statements use the assert keyword•Assert statements raise AssertionError•Based on bool test expressions ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  7. 7. Assert Statements keyword >>> assert 1 == 1 ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  8. 8. Assert Statements expression >>> assert 1 == 1 ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  9. 9. Assert Statements >>> assert expression is almost the same as: >>> if not expression: ... raise AssertionError() >>> ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  10. 10. Assert Statements >>> assert 1 == 1 >>> assert 1 == 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError >>> ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  11. 11. Assert Statements•A second optional expression on the assert statement provides a message for the AssertionError•This helps you distinguish one assertion from another ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  12. 12. Assert Statements second expression >>> assert 1 == 2, "Reality check" ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  13. 13. Assert Statements assert expression1, expression2 is almost the same as: if not expression1: raise AssertionError(expression2) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  14. 14. Assert Statements >>> assert 1 == 2, "Reality check" Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError: Reality check >>> ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  15. 15. Assert Statements•Assertions may be sprinkled liberally throughout your code to check that your code is running as expected•Think of assertions as Pythons reality check•You decide what "reality" is ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  16. 16. Assert Statements bigbiz.py: profit = bottom_line(today) assert profit > 0, "Unacceptable!" projection = growth(tomorrow) assert projection > profit, "UR fired!" ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  17. 17. Assert Statements•Assertions usually generate unhandled exceptions which halt your program ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  18. 18. Assert Statements bigbiz.py: def bottom_line(timestamp): """Compute the profit on date.""" Text return -1e6 ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  19. 19. Assert Statements > python bigbiz.py Traceback (most recent call last): File "bigbiz.py", line 20, in <module> assert profit > 0, "Unacceptable!" AssertionError: Unacceptable! > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  20. 20. Assert Statements•By using Pythons -i command line switch, you may interactively inspect what went wrong where the assertion was raised ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  21. 21. Assert Statements > python -i bigbiz.py Traceback (most recent call last): File "bigbiz.py", line 20, in <module> assert profit > 0, "Unacceptable!" AssertionError: Unacceptable! >>> profit -1000000.0 >>> ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  22. 22. Assert Statements•By using Pythons -i command line switch, you may use also Pythons debugger to see what went wrong at the point of assertion ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  23. 23. Assert Statements > python -i bigbiz.py Traceback (most recent call last): File "bigbiz.py", line 20, in <module> assert profit > 0, "Unacceptable!" AssertionError: Unacceptable! >>> import pdb >>> pdb.pm() > /Users/cbc/pyohio/bigbiz.py(20)<module>() -> assert profit > 0, "Unacceptable!" (Pdb) profit -1000000.0 (Pdb) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  24. 24. Assert Statements•Assertions may be turned off by "optimizing" Python with the -O command line switch ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  25. 25. Assert Statements > python -O >>> assert 1 == 2 >>> ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  26. 26. Assert Statements > python -O bigbiz.py Profit is -1000000.00 USD. Projected profit is -2000000.00 USD. > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  27. 27. Assert Statements•Its a fine line whether assert statements are testing or debugging•Assert statements are slightly more sophisticated than using print•But assert statements form the basis for testing in Python•In Python, a test is an assertion of an expected result ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  28. 28. Unittest Module•Unittest is "batteries included" in Python•Unittest helps you separate test code from the code under test•Unittest helps you write tests before code•Unittest helps you organize and discover all your tests•Unittest hooks into many other Python tools ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  29. 29. Unittest Module >>> import unittest >>> dir(unittest) [BaseTestSuite, FunctionTestCase, SkipTest, TestCase, TestLoader, TestProgram, TestResult, TestSuite, TextTestResult, TextTestRunner, _TextTestResult, __all__, __builtins__, __cached__, __doc__, __file__, __name__, __package__, __path__, __unittest, case, defaultTestLoader, expectedFailure, findTestCases, getTestCaseNames, installHandler, loader, main, makeSuite, registerResult, removeHandler, removeResult, result, runner, signals, skip, skipIf, skipUnless, suite, util] >>> ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  30. 30. TestCase Class•unittest.TestCase is a class•You create TestCase subclasses•You add methods whose names start with "test" to your TestCase subclass ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  31. 31. TestCase Class•Each test method you supply in your subclass executes a TestCase supplied method whose name starts with "assert"•A TestCase provides what is known as a "test fixture" in testing parlance•The unittest module provides many ways to run the test methods of your text fixture ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  32. 32. TestCase Class test_operator.py: """Demonstrate the unittest module.""" Text import operator import unittest ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  33. 33. TestCase Class test_operator.py: class TestOperator(unittest.TestCase): Text """Test the operator module.""" ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  34. 34. TestCase Class test_operator.py: def test_add(self): """Test the add function.""" Text self.assertEqual(operator.add(2, 2), 2 + 2) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  35. 35. TestCase Class test_operator.py: def test_sub(self): """Test the sub function.""" Text self.assertEqual(operator.sub(4, 2), 4 - 2) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  36. 36. TestCase Class test_operator.py: def test_mul(self): """Test the mul function.""" Text self.assertEqual(operator.mul(2, 2), 2 * 2) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  37. 37. TestCase Class test_operator.py: if __name__ == "__main__": Text unittest.main() ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  38. 38. main Class•unittest.main is also a class•unittest.main is normally only used within a script containing test fixtures•When unittest.main is instantiated, all of the tests in the scripts namespace are loaded and run ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  39. 39. main Class > python test_operator.py ... -------------------------------------- Ran 3 tests in 0.001s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  40. 40. TestLoader Class•Notice that nowhere does it appear that your script has instantiated your TestCase subclass or execute any of its methods•unittest.main instead instantiates a special unittest.TestLoader class which has methods to search your module for TestCase classes and instantiate them ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  41. 41. TestRunner Class•Once the TestLoader instance created by unittest.main discovers and instantiates the TestCase in your script, unittest.main instantiates a special unittest.TestRunner class which has methods to run the methods of your TestCase instances•unittest.main takes care of handling TestLoaders and TestRunners for you! ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  42. 42. TestRunner Class TestCase unittest.main (superclass) (instance) createTests() TestOperator discover() TestLoader (subclass) (instance) runTests() TestOperator run() TestRunner (instance) (instance) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  43. 43. main Class test_operator.py: if __name__ == "__main__": Text unittest.main(verbosity=2) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  44. 44. main Class > python test_operator.py test_add (__main__.TestOperator) Test the add function. ... ok test_mul (__main__.TestOperator) Test the mul function. ... ok test_sub (__main__.TestOperator) Test the sub function. ... ok -------------------------------------- Ran 3 tests in 0.001s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  45. 45. main Class•Notice that your tests did not run in the same order in which they were defined•unittest.main loads the test methods from your TestCase instances __dict__ attribute•Dictionaries are unordered•unittest.main() runs the test methods in your Pythons built-in order for strings ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  46. 46. TestCase Class test_operator.py: def test_add(self): """Test the add function.""" Text self.assertEqual(operator.add(2, 2), 2 + 3) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  47. 47. TestCase Class > python test_operator.py F.. ====================================== FAIL: test_add (__main__.TestOperator) Test the add function. -------------------------------------- Traceback (most recent call last): File "test_operator.py", line 13, in test_add self.assertEqual(operator.add(2, 2), 2 + 3) AssertionError: 4 != 5 -------------------------------------- Ran 3 tests in 0.082s FAILED (failures=1) > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  48. 48. TestCase Class test_operator.py: def test_add(self): """Test the add function.""" Text self.assertEqual(operator.add(2, 2), 2 + "2") ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  49. 49. TestCase Class > python test_operator.py E.. ================================================ ERROR: test_add (__main__.TestOperator) Test the add function. ------------------------------------------------ Traceback (most recent call last): File "test_operator.py", line 13, in test_add self.assertEqual(operator.add(2, 2), 2 + "2") TypeError: unsupported operand type(s) for +: int and str ------------------------------------------------ Ran 3 tests in 0.001s FAILED (errors=1) > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  50. 50. TestResult Class•Running a test results in one of three outcomes: ★ Success (expected result) ★ Failure (unexpected result) ★ Error (error running the test)•The outcomes of all tests are accumulated in a unittest.TestResult instance ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  51. 51. TestResult Class•Most of the time you will not need to create your own TestResult instances•Most of the ways you will run tests will instantiate and report a TestResult for you•But to run a test always requires a TestResult instance somewhere ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  52. 52. TestResult Class > python -m unittest test_operator ... -------------------------------------- Ran 3 tests in 0.000s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  53. 53. TestResult Class > python -m unittest test_operator.TestOperator ... -------------------------------------- Ran 3 tests in 0.000s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  54. 54. TestResult Class > python -m unittest test_operator.TestOperator.test_add . -------------------------------------- Ran 1 test in 0.000s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  55. 55. TestResult Class > python -m unittest test_operator.py ... -------------------------------------- Ran 3 tests in 0.000s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  56. 56. TestResult Class > python -m unittest -v test_operator test_add (test_operator.TestOperator) Test the add function. ... ok test_mul (test_operator.TestOperator) Test the mul function. ... ok test_sub (test_operator.TestOperator) Test the sub function. ... ok -------------------------------------- Ran 3 tests in 0.001s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  57. 57. TestResult Class > python -m unittest -h Usage: python -m unittest [options] [tests] Options: -h, --help Show this message -v, --verbose Verbose output -q, --quiet Minimal output -f, --failfast Stop on first failure -c, --catch Catch control-C and display results -b, --buffer Buffer stdout and stderr during test runs [tests] can be a list of any number of test modules, classes and test methods. ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  58. 58. load_tests Protocol > python -m unittest ....... -------------------------------------- Ran 7 tests in 0.000s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  59. 59. load_tests Protocol Alternative Usage: python -m unittest discover [options] Options: -s directory Directory to start discovery (. default) -p pattern Pattern to match test files (test*.py default) -t directory Top level directory of project (default to start directory) For test discovery all test modules must be importable from the top level directory. ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  60. 60. TestCase Class•Notice that TestCase.assertEqual does not appear to raise an unhandled AssertionError•The TestRunner instance handles the AssertionError for failing tests and updates the TestResult instance•TestCase.assertEqual is but one of many test methods you may use in your tests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  61. 61. TestCase Class Method Tests If assertEqual(a, b) a == b assertNotEqual(a, b) a != b assertTrue(x) bool(x) is True assertFalse(x) bool(x) is False assertIs(a, b) a is b assertIsNot(a, b) a is not b assertIsNone(x) x is None assertIsNotNone(x) x is not None assertIn(a, b) a in b assertNotIn(a, b) a not in b assertIsInstance(a, b) isinstance(a, b) assertNotIsInstance(a, b) not isinstance(a, b) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  62. 62. TestCase Class•You not only need to test if your code produces expected results, you also need to test if your code handles unexpected results in an expected manner! ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  63. 63. TestCase Class test_operatorNG.py: def test_add_str(self): """Test bad args for add.""" Text with self.assertRaises(TypeError): operator.add(2, "2") ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  64. 64. TestCase Class > python -m unittest test_operatorNG .... -------------------------------------- Ran 4 tests in 0.000s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  65. 65. TestCase Class Method Tests If assertRaises(exception) exception raised exception raised and assertRaisesRegex(exception, regex) message matches regex assertWarns(warning) warning raised warning raised and assertWarnsRegex(warning, regex) message matches regex ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  66. 66. TestCase Class Method Tests If assertAlmostEqual(a, b) round(a-b, 7) == 0 assertNotAlmostEqual(a, b) round(a-b, 7) != 0 assertGreater(a, b) a > b assertGreaterEqual(a, b) a >= b assertLess(a, b) a < b assertLessEqual(a, b) a <= b assertRegex(s, re) s matches regex assertNotRegex(s, re) s does not match regex a and b have the same assertCountEqual(a, b) elements in the same number, regardless of order ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  67. 67. TestCase Class Method Compares assertMultiLineEqual(a, b) Strings assertSequenceEqual(a, b) Sequences assertListEqual(a, b) Lists assertTupleEqual(a, b) Tuples assertSetEqual(a, b) Sets and Frozensets assertDictEqual(a, b) Dictionaries ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  68. 68. TestCase Class•Plus many more! >>> [attr for attr ... in dir(unittest.TestCase) ... if attr.startswith(assert)] ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  69. 69. TestCase Class >>> help(unittest.TestCase. ... assertDictContainsSubset) Help on function assertDictContainsSubset in module unittest.case: assertDictContainsSubset(self, subset, dictionary, msg=None) Checks whether dictionary is a superset of subset. ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  70. 70. TestSuite Class test_operatorNG2.py: """Demonstrate the unittest module.""" Text import operator import unittest ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  71. 71. TestSuite Class test_operatorNG2.py: class TestAdd(unittest.TestCase): Text """Test the add function.""" ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  72. 72. TestSuite Class test_operatorNG2.py: def test_add_int(self): """Test with ints.""" Text self.assertEqual(operator.add(2, 2), 2 + 2) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  73. 73. TestSuite Class test_operatorNG2.py: def test_add_str(self): """Test with strs.""" Text with self.assertRaises(TypeError): operator.add(2, "2") ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  74. 74. TestSuite Class test_operatorNG2.py: class TestSub(unittest.TestCase): Text """Test the sub function.""" ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  75. 75. TestSuite Class test_operatorNG2.py: def test_sub_int(self): """Test with ints.""" Text self.assertEqual(operator.sub(4, 2), 4 - 2) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  76. 76. TestSuite Class test_operatorNG2.py: def test_sub_str(self): """Test with strs.""" Text with self.assertRaises(TypeError): operator.sub(4, "2") ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  77. 77. TestSuite Class test_operatorNG2.py: class TestMul(unittest.TestCase): Text """Test the mul function.""" ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  78. 78. TestSuite Class test_operatorNG2.py: def test_mul_int(self): """Test with ints.""" Text self.assertEqual(operator.mul(2, 2), 2 * 2) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  79. 79. TestSuite Class test_operatorNG2.py: def test_mul_str(self): """Test with strs.""" Text self.assertEqual(operator.mul(2, "2"), "22") ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  80. 80. TestSuite Class test_operatorNG2.py: str_suite = unittest.TestSuite() Text str_suite.addTest(TestAdd("test_add_str")) str_suite.addTest(TestSub("test_sub_str")) str_suite.addTest(TestMul("test_mul_str")) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  81. 81. TestSuite Class test_operatorNG2.py: if __name__ == "__main__": Text unittest.main() ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  82. 82. TestSuite Class•Objects you have bound in the test_operatorNG2 namespace: •TestAdd class •TestSub class •TestMul class •str_suite instance ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  83. 83. TestSuite Class > python test_operatorNG2.py ...... -------------------------------------- Ran 6 tests in 0.001s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  84. 84. TestSuite Class > python -m unittest test_operatorNG2.str_suite ... -------------------------------------- Ran 3 tests in 0.000s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  85. 85. TestSuite Class > python -m unittest -v test_operatorNG2.str_suite test_add_str (test_operatorNG2.TestAdd) Test with strs. ... ok test_sub_str (test_operatorNG2.TestSub) Test with strs. ... ok test_mul_str (test_operatorNG2.TestMul) Test with strs. ... ok -------------------------------------- Ran 3 tests in 0.001s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  86. 86. Organizing Tests pyohio-+ bin/python pycamp-+ __init__.py setup.py fibonacci.py triangle.py tests-+ __init__.py test_fibonacci.py test_triangular.py ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  87. 87. Organizing Tests > python pycamp/fibonacci.py 100 1 2 3 5 8 13 21 34 55 89 > python >>> from pycamp.fibonacci import fib >>> fib(100) [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] >>> ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  88. 88. Organizing Tests > python pycamp/triangular.py 100 1 3 6 10 15 21 28 36 45 55 66 78 91 > python >>> from pycamp.triangular import tri >>> tri(100) [1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 91] >>> ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  89. 89. Organizing Tests pycamp/tests/test_fibonacci.py: """Tests for the fibonacci module.""" Text from pycamp import fibonacci import unittest ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  90. 90. Organizing Tests pycamp/tests/test_fibonacci.py: class TestFibonacci(unittest.TestCase): Text """Test fibonaccis functions.""" ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  91. 91. TestCase Class•TestCase also supplies methods you override•TestCase.setUp() is called before every test method you supply in your subclass•TestCase.tearDown() is called after every test method you supply in your subclass ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  92. 92. TestCase Class•Your TestCase subclasses, along with all the test methods you supply, and all the TestCase supplied methods you override, possibly all bundled up into a TestSuite, are collectively known as a "test fixture" in testing parlance ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  93. 93. Organizing Tests pycamp/tests/test_fibonacci.py: def setUp(self): """Test fixture build.""" Text self.lessThan100 = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ] ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  94. 94. Organizing Tests pycamp/tests/test_fibonacci.py: def test_fib_100(self): """Test fib for numbers < 100.""" Text self.assertEqual(fibonacci.fib(100), self.lessThan100) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  95. 95. Organizing Tests pycamp/tests/test_fibonacci.py: def test_fib_10(self): """Test fib for numbers < 10.""" Text self.assertEqual(fibonacci.fib(10), self.lessThan100[:5]) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  96. 96. Organizing Tests pycamp/tests/test_fibonacci.py: if __name__ == "__main__": Text unittest.main() ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  97. 97. Organizing Tests pycamp/tests/test_triangular.py: """Tests for the triangular module.""" Text from pycamp import triangular import unittest ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  98. 98. Organizing Tests pycamp/tests/test_triangular.py: class TestTriangular(unittest.TestCase): Text """Test triangulars functions.""" ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  99. 99. Organizing Tests pycamp/tests/test_triangular.py: def setUp(self): """Test fixture build.""" Text self.lessThan100 = [1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 91, ] ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  100. 100. Organizing Tests pycamp/tests/test_triangular.py: def test_tri_100(self): """Test tri for numbers < 100.""" Text self.assertEqual(triangular.tri(100), self.lessThan100) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  101. 101. Organizing Tests pycamp/tests/test_triangular.py: def test_tri_10(self): """Test tri for numbers < 10.""" Text self.assertEqual(triangular.tri(10), self.lessThan100[:3]) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  102. 102. Organizing Tests pycamp/tests/test_triangular.py: if __name__ == "__main__": Text unittest.main() ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  103. 103. Organizing Tests > python -m unittest discover -s pycamp -t . .... -------------------------------------- Ran 4 tests in 0.001s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  104. 104. Organizing Tests pycamp/setup.py: """Setup for pycamp package.""" Text from setuptools import setup, find_packages ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  105. 105. Organizing Tests pycamp/setup.py: setup( name="pycamp", version="1.0", Text packages=find_packages(), author="Chris Calloway", author_email="cbc@chriscalloway.org", ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  106. 106. Organizing Tests pycamp/setup.py: description="Testing Fundamentals", license="PSF", Text keywords="testing pycamp", url="http://pycamp.org", test_suite="pycamp.tests", ) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  107. 107. Organizing Tests > python pycamp/setup.py test running test ..lots of output omitted for brevity.. -------------------------------------- Ran 4 tests in 0.001s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  108. 108. Organizing Tests > python pycamp/setup.py test ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  109. 109. Organizing Tests > python pycamp/setup.py install ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  110. 110. Organizing Tests > python pycamp/setup.py register ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  111. 111. Unittest Module•unittest provides nice separation of tests from code•One person can write tests, while another writes code to make tests pass•unittest provides fine grain control over what tests to run when•unittest conforms to industry standard testing ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  112. 112. Unittest Module•However, it can be difficult to keep tests and code in sync•Also, writing code to test code can also be more difficult than the code under test•What about testing and debugging the test code?•Reading unittest tests is a poor way to figure out how code works ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  113. 113. Doctest Module•Informally, even without written tests, you probably already test your code by simply using it as it was meant to be used•Youve probably imported your code at a Python prompt and inspect how it works manually•You just dont yet have a way of repeating that informal testing in an automated manner•What you need is the doctest module ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  114. 114. Doctest Module pyohio-+ bin/python pycampNG-+ __init__.py setup.py fibonacci.py triangle.py tests-+ __init__.py test_pycamp.py ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  115. 115. Doctest Module pycampNG/fibonacci.py: """A module of functions about non-zero Fibonacci numbers. Text >>> import fibonacci >>> """ ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  116. 116. Doctest Module pycampNG/fibonacci.py: def fib(n): """Return the sequence of non-zero Fibonacci numbers less than n. Text fib(n) -> [0 < fibonacci numbers < n] where n in an int. ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  117. 117. Doctest Module pycampNG/fibonacci.py: >>> lessThan100 = [1, 2, 3, 5, 8, 13, ... 21, 34, 55, 89] >>> fib(100) == lessThan100 Text True >>> fib(10) == lessThan100[:5] True """ ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  118. 118. Doctest Module pycampNG/triangular.py: """A module of functions about non-zero triangular numbers. Text >>> import triangular >>> """ ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  119. 119. Doctest Module pycampNG/triangular.py: def tri(n): """Return the sequence of non-zero triangular numbers less than n. Text tri(n) -> [0 < triangular numbers < n] where n in an int. ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  120. 120. Doctest Module pycampNG/triangular.py: >>> lessThan100 = [1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 91] Text >>> tri(100) == lessThan100 True >>> tri(10) == lessThan100[:3] True """ ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  121. 121. Doctest Module > python -m doctest pycampNG/fibonacci.py > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  122. 122. Doctest Module > python -m doctest -v pycampNG/fibonacci.py Trying: import fibonacci Expecting nothing ok ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  123. 123. Doctest Module Trying: lessThan100 = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] Expecting nothing ok ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  124. 124. Doctest Module Trying: fib(100) == lessThan100 Expecting: True ok ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  125. 125. Doctest Module Trying: fib(10) == lessThan100[:5] Expecting: True ok ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  126. 126. Doctest Module 2 items passed all tests: 1 tests in fibonacci 3 tests in fibonacci.fib 4 tests in 2 items. 4 passed and 0 failed. Test passed. > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  127. 127. Doctest Module > python -m doctest pycampNG/triangular.py > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  128. 128. Doctest Module pycampNG/fibonacci.py: if __name__ == __main__: if sys.argv[1].lower() == test: import doctest Text doctest.testmod() else: print(" ".join([str(x) for x in fib(int(sys.argv[1]))])) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  129. 129. Doctest Module pycampNG/triangular.py: if __name__ == __main__: if sys.argv[1].lower() == test: import doctest Text doctest.testmod() else: print(" ".join([str(x) for x in tri(int(sys.argv[1]))])) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  130. 130. Doctest Module > python pycampNG/fibonacci.py test > python pycampNG/fibonacci.py 100 1 2 3 5 8 13 21 34 55 89 > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  131. 131. Doctest Module > python pycampNG/triangular.py test > python pycampNG/triangular.py 100 1 3 6 10 15 21 28 36 45 55 66 78 91 > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  132. 132. Doctest Module•But what about setuptools.setup?•The test_suite argument of setup triggers unittest discovery, not doctest discovery•What you need is a way to turn doctests into unittests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  133. 133. Doctest Module•The doctest.DocTestSuite() function searches a module for doctests and converts them into a unittest.TestSuite instance•Now all you need is a way to communicate your TestSuite instance(s) to unittest discovery ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  134. 134. load_tests Protocol def load_tests(loader, tests, pattern): ... return tests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  135. 135. load_tests Protocol unittest.TestLoader def load_tests(loader, tests, pattern): ... return tests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  136. 136. load_tests Protocol def load_tests(loader, unittest.TestSuite tests, pattern): ... return tests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  137. 137. load_tests Protocol def load_tests(loader, tests, "test*.py" pattern): ... return tests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  138. 138. load_tests Protocol def load_tests(loader, tests, pattern): ... return tests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  139. 139. load_tests Protocol pycampNG/tests/test_pycamp.py: import doctest Text from pycampNG import fibonacci from pycampNG import triangular ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  140. 140. load_tests Protocol pycampNG/tests/test_pycamp.py: def load_tests(loader, tests, pattern): tests.addTests( doctest.DocTestSuite(fibonacci)) Text tests.addTests( doctest.DocTestSuite(triangular)) return tests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  141. 141. load_tests Protocol pycampNG/tests/test_pycamp.py: def load_tests(loader, tests, pattern): tests.addTests( doctest.DocTestSuite(fibonacci)) Text tests.addTests( doctest.DocTestSuite(triangular)) return tests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  142. 142. load_tests Protocol pycampNG/tests/test_pycamp.py: def load_tests(loader, tests, pattern): tests.addTests( doctest.DocTestSuite(fibonacci)) Text tests.addTests( doctest.DocTestSuite(triangular)) return tests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  143. 143. load_tests Protocol pycampNG/tests/test_pycamp.py: def load_tests(loader, tests, pattern): tests.addTests( doctest.DocTestSuite(fibonacci)) Text tests.addTests( doctest.DocTestSuite(triangular)) return tests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  144. 144. load_tests Protocol pycamp/setup.py: setup( name="pycampNG", Text ... test_suite="pycampNG.tests", ) ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  145. 145. load_tests Protocol > python pycampNG/setup.py test running test ..lots of output omitted for brevity.. -------------------------------------- Ran 4 tests in 0.001s OK > ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  146. 146. Doctest Module Together, the doctest.DocTestSuite() function and the load_tests protocol from the unittest module enable you to use all the tools available for unittests with doctests ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  147. 147. Python Testing Tools Taxonomy ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  148. 148. Test Driven Development•Doctests enable you to do Test Driven Development (TDD)•TDD is where you write tests for your code before you write code•Then you write code to make your tests pass ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  149. 149. Test Driven Development•When all your tests pass, then you have finished coding•You can develop your code incrementally, writing one test at a time, then getting that one test to pass•That means you can stop coding at any time ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  150. 150. Test Driven Development•If your code needs more features, then what you really need is more tests, and code which makes those tests pass•Writing tests lets you see what the API for your code is up front, instead of having it designed haphazardly•Writing tests can provide the documentation for your code ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  151. 151. Test Driven Development ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  152. 152. Tomorrow 12:15pm in Barbie Tootle ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  153. 153. Thank You pycamp@trizpug.org ProgrammingPyCamp™ Copyright © 2012 Trizpug For The People
  1. ¿Le ha llamado la atención una diapositiva en particular?

    Recortar diapositivas es una manera útil de recopilar información importante para consultarla más tarde.

×