71 | | * * easing refactoring (changes can be more rapidly verified not to create new bugs), |
72 | | * * promoting refactoring (dividing units into testable pieces also creates more reusable pieces), |
73 | | * * standing in for specification documents (i.e. describing by example what the code needs to do). |
| 71 | ** easing refactoring (changes can be more rapidly verified not to create new bugs), |
| 72 | ** promoting refactoring (dividing units into testable pieces also creates more reusable pieces), |
| 73 | ** standing in for specification documents (i.e. describing by example what the code needs to do). |
82 | | nose is a python module/command which finds and runs tests. nose is suitable as it has been widely adopted in the python community, allows standard test specifications and is highly configurable and customisable, without confusing "magical" behaviour. To work with web2py, a plugin has been written, which means that nosetests isn't run in the normal way, although we'll aim for that as much as possible. |
| 83 | [http://readthedocs.org/docs/nose/ nose] is a python module/command which finds and runs tests. nose is suitable as it has been widely adopted in the python community, allows standard test specifications and is highly configurable and customisable, without confusing "magical" behaviour. Documentation is [http://readthedocs.org/docs/nose/ here]. |
| 84 | |
| 85 | To work with web2py, a plugin has been written, which means that nosetests isn't run in the normal way, although we'll aim for that as much as possible. Extra arguments are just passed on to nose, so the command's argument format is the same as original as the original nosetest command. |
| 88 | |
| 89 | === Writing unit tests === |
| 90 | |
| 91 | When writing unit tests, note that nose uses a convention over configuration approach when finding tests. i.e. if it looks like a test, then nose assumes it is a test. |
| 92 | |
| 93 | To make your test look like a test, there are two options: |
| 94 | |
| 95 | # easy: write a procedure whose name starts with "test_" |
| 96 | # advanced: inherit from unittest.TestCase and write your tests as described in [http://docs.python.org/library/unittest.html] |
| 97 | |
| 98 | {{{ |
| 99 | # examples: |
| 100 | |
| 101 | def test_addition(): |
| 102 | assert 1 + 1 == 2 |
| 103 | |
| 104 | import unittest |
| 105 | class AdditionTest(unittest.TestCase): |
| 106 | def test_positive(test): |
| 107 | assert 1+1 == 2 |
| 108 | |
| 109 | def test_negative(test): |
| 110 | assert -1 + -1 == -2 |
| 111 | }}} |
| 112 | |
| 113 | Currently these tests are stored in {{{/tests}}}. Duplicate the module folder there of the unit being tested inside the tests/ folder. We know this duplication is not ideal, this may well change in future and tests be placed nearer the code being tested. |
| 114 | |
| 115 | '''Advice:''' |
| 116 | |
| 117 | One unittest.TestCase per unit (procedure, method or function). This makes test output easy to follow as it is what unittest expects. I.e. don't test several units in one TestCase. |
| 118 | You can just use asserts instead of the cumbersome test.assertEquals etc. methods which often don't do what you need. nose can introspect the stack to make meaningful messages. |
| 119 | Avoid inheritance trees with unittests as the unittest.TestCase isn't really designed for inheritance, more as a convenient place to put the tests. |
| 120 | Break test methods up into smaller methods. Non-test code can be extracted out into external procedures/functions which are easier to reuse. |
| 121 | Read the nose documentation regarding writing tests: [http://readthedocs.org/docs/nose/en/latest/writing_tests.html] |
| 122 | Read this too: [http://ivory.idyll.org/articles/nose-intro.html] |