with a solid test suite, you can make big changes, confident that the externally visible behavior will remain the same
"Code without tests is broken by design."
$ sudo pip install virtualenvwrapper
$ virtualenvwrapper.sh
$ mkvirtualenv test --no-site-packages
$ workon test
$ pip install nose coverage mock Django django-nose
$ sudo pip install virtualenv
$ virtualenv test --no-site-packages
$ ~/.virtualenvs/test/bin/activate
sudo pip install virtualenvwrapper
mkvirtualenv test --no-site-packages
workon test
$ pip install nose
$ pip install coverage
$ pip install mock
$ pip install Django
# Install django-nose $ pip install django-nose
The doctest module searches for pieces of text that look like interactive Python sessions, and then executes those sessions to verify that they work exactly as shown.
def fact(n):
"""
Factorial function
:arg n: Number
:returns: factorial of n
>>> fact(0)
1
>>> fact(4)
24
"""
if n == 0:
return 1
return n * fact(n -1)
$ python -m doctest factorial.py
# You can add the following at the end of the file if __name__ == '__main__': import doctest doctest.test_method()
# Execute tests from shell as below. $ python factorial.py
In computer programming, unit testing is a method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine if they are fit for use.
import sys
def fact(n):
"""
Factorial function
:arg n: Number
:returns: factorial of n
"""
if n == 0:
return 1
return n * fact(n -1)
def div(n):
"""
Just divide
"""
res = 10 / n
return res
def main(n):
res = fact(n)
print res
if __name__ == '__main__':
if len(sys.argv) > 1:
main(int(sys.argv[1]))
$ python factorial.py
120
import unittest
from factorial import fact class TestFactorial(unittest.TestCase): """ Our basic test class """ def test_fact(self): """ The actual test. Any method which starts with ``test_`` will considered as a test case. """ res = fact(5) self.assertEqual(res, 120)
if __name__ == '__main__': unittest.main()
$ python factorial_test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
$ python -m unittest factorial_test
import unittest class SampleTestCase(unittest.TestCase): @classmethod def setUpClass(cls): # setup environment persistent for the entire test case run
...
def setUp(self): # setup environment for each test method
...
def test_case1(self): # some test code
.... ...
def tearDown(self): # Undo changes made in setUp()
...
@classmethod def tearDownClass(cls): # Undo changes made in setUpClass()
...
Method Checks that New in
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 2.7
assertIsNot(a, b) a is not b 2.7
assertIsNone(x) x is None 2.7
assertIsNotNone(x) x is not None 2.7
assertIn(a, b) a in b 2.7
assertNotIn(a, b) a not in b 2.7
assertIsInstance(a, b) isinstance(a, b) 2.7
assertNotIsInstance(a, b) not isinstance(a, b) 2.7
nose extends unittest to make testing easier.
# nosetests finds all tests in the current directory # and runs them. $ nosetests
# You can also run tests from a particular module/package
$ nosetests factorial.test_factorial
# You can even run a particular Test Case
$ nosetests factorial.test_factorial:TestFactorial
# Or a test method
$ nosetests factorial.test_factorial:TestFactorial.test_fact
Coverage.py is a tool for measuring code coverage of Python programs.
$ coverage -x test_factorial.py
$ coverage -rm
Name Stmts Miss Cover Missing
----------------------------------------------
factorial 14 6 57% 25-26, 30-31, 35-36
test_factorial 8 0 100%
----------------------------------------------
TOTAL 22 6 73%
$ cd ~/test-your-code
$ nosetests --with-coverage --cover-erase --cover-tests
.......
Name Stmts Miss Cover Missing
-----------------------------------------------------------------------------------
test_your_code 0 0 100%
test_your_code.examples 0 0 100%
test_your_code.examples.factorial 0 0 100%
test_your_code.examples.factorial.factorial 14 6 57% 25-26, 30-31, 35-36
test_your_code.examples.factorial.test_factorial 8 1 88% 19
test_your_code.examples.fizzbuzz 0 0 100%
test_your_code.examples.fizzbuzz.fizzbuzz 15 1 93% 30
test_your_code.examples.fizzbuzz.test_fizzbuz 15 1 93% 24
test_your_code.examples.fizzbuzz.test_fizzbuzz_main 9 0 100%
-----------------------------------------------------------------------------------
TOTAL 61 9 85%
----------------------------------------------------------------------
Ran 7 tests in 0.026s
OK
import sys, requests, json
URL = "https://api.github.com/users/{user}/repos"
def most_watched_repos(user, n):
url = URL.format(user=user)
resp = requests.get(url, timeout=10)
repos_list = json.loads(resp.content)
return [i['html_url'] for i in sorted(
repos_list, key=lambda i: -1 * i['watchers'])][:n]
if __name__ == '__main__':
user = sys.argv[1]
n = int(sys.argv[2])
print most_watched_repos(user, n)
>>> import mock >>> m = mock.Mock() >>> m.called False >>> m.call_count 0 >>> m() >>> m.called True >>> m.call_count 1
>>> m.return_value = 'foo'
>>> m()
'foo'
>>> m.side_effect = Exception('Boom!') >>> m() Traceback (most recent call last): ... Exception: Boom!
>>> mock = Mock()
>>> mock.method(1, 2, 3, test='wow')
>>> mock.method.assert_called_with(1, 2, 3, test='wow')
>>> mock = Mock(return_value=None)
>>> mock('foo', bar='baz')
>>> mock.assert_called_once_with('foo', bar='baz')
>>> mock('foo', bar='baz')
>>> mock.assert_called_once_with('foo', bar='baz')
Traceback (most recent call last):
...
AssertionError: Expected to be called once. Called 2 times.
>>> mock = Mock(return_value=None)
>>> mock(1, 2, arg='thing')
>>> mock('some', 'thing', 'else')
>>> mock.assert_any_call(1, 2, arg='thing')
>>> mock = Mock(return_value=None)
>>> mock('hello')
>>> mock.called
True
>>> mock.reset_mock()
>>> mock.called
False
The patch decorators are used for patching objects only within the scope of the function they decorate. They automatically handle the unpatching for you, even if exceptions are raised. All of these functions can also be used in with statements or as class decorators.
>>> @patch('__main__.SomeClass')
... def function(normal_argument, mock_class):
... print mock_class is SomeClass
...
>>> function(None)
True