search by tags

for the user

adventures into the land of the command line

unit testing in python

You’ll need this guy:

import unittest

Then you can create a test class:

class my_test(unittest.TestCase):
    def test_something(self):
        a = 1
        b = 2
        self.assertNotEqual(a, b)

if __name__ == '__main__':
    unittest.main()

Run it!

$ python tests.py
.....
----------------------------------------------------------------------
Ran 1 tests in 0.000s

OK

Noice, assert methods for python 2 are here.

To mock stuff out, you gotta install mock first

$ pip install mock

then you can do it

from mock import MagicMock, Mock, patch
import myapp

mock out some import

sys.modules['somefile'] = Mock()

mock out some external crap and tell it what to pretend to be

@patch('redis.StrictRedis.hget', return_value="True")
def test_some_function(self, some_db_call):
    .
    .
    .
    self.assertEqual(response.status_code, 200)

mock out external crap where the function being tested has multiple of the same thing to mock with different return values

@patch('redis.StrictRedis.hget', side_effect=['True', 'False'])
def test_some_function(self, some_db_call):
    .
    .
    .
    self.assertEqual(response.status_code, 201)

unit testing flask, install the package

$ pip install Flask-Testing

then

from flask.ext.testing import TestCase
import myapp
from flask import Flask, request

class LoginTests(unittest.TestCase):

    def setUp(self):
        myapp.app.config['TESTING'] = True
        self.app = myapp.app.test_client()

    def tearDown(self):
        pass

    def test_incorrect_request_method(self):
        response = self.app.get('/login')
        self.assertEqual(response.status_code, 405)

if __name__ == '__main__':
    unittest.main()

to remove any files created by the test, such as a mocked logfile

# to remove dummy log files created by the mock
files = [f for f in os.listdir('.') if os.path.isfile(f)]
for f in files:
  if f[-4:] == '.log':
    os.remove(f)

to check code coverage, you can use coverage.py

$ pip install coverage

run you test using coverage, instead of python

$ coverage run tests.py
.....
----------------------------------------------------------------------
Ran 1 tests in 0.000s

OK

check your coverage

$ coverage report -m
Name       Stmts   Miss  Cover   Missing
----------------------------------------
index.py    2056   1526    26%   94-95, 99-107, 110-119, 1247-3180
tests.py     690      0   100%
----------------------------------------
TOTAL       2746   1526    44%

if you decide to split your unit tests into neatly organised folders and you want to run all of them at once, you can do something like this:

.
├── tests
│   ├── __init__.py
│   ├── tests_main.py
│   ├── auth
│   │   ├── __init__.py
│   │   ├── tests_login.py
│   ├── comms
│   │   ├── __init__.py
│   │   ├── tests_emailer.py
│   └── transaction
│       ├── __init__.py
│       ├── tests_transactions.py

make sure each folder including the root of the tests folder has an init file to make it into a module.

then you can use (as of python 2.7):

$ python -m unittest discover -s tests

this will recurse the directory names ‘tests’ and execute all of the test modules within.

to run just one of the modules

$ python -m unittest tests.tests_main
$ python -m unittest tests.auth.tests_login
$ python -m unittest tests.comms.tests_emailer
$ python -m unittest tests.transaction.tests_transactions

and just one of the specific tests within a specific module

$ python -m unittest tests.auth.tests_login.LoginTests.test_successful_login