Unit Test
General Rules
A testing unit should focus on one tiny bit of functionality and prove it correct
Each test unit must be fully independent
Try hard to make tests that run fast
Learn your tools and learn how to run a single test or a test case
Always run the full test suite before a coding session, and run it again after
Runs all tests before pushing code to a shared repository
Use long and descriptive names for testing functions
Test Outcomes
ok, the test passes
FAIL, the test does not pass, and raises an AssertionError exception
ERROR, the test raises an exception other than AssertionError
Layout and pytest
Source Code
# get source code
git clone https://github.com/lin-chen-Langley/prime
Option 1. pytest
Use pytest instead of default test, the default test may ignore some exceptions
Implement test (2 options)
- python setup.py test, aliase pytest to test
- python setup.py pytest
pytest will search for test_*.py or *_test.py files in test folder, imported by their test package name, collect test_ prefixed test functions or methods as test items
test does not install dependencies to system, it install the copies of dependencies to .eggs in the project folder
test files must have unique names, the test files will be imported as top-level modules by adding test/ to sys.path
developer
python setup.py test # assure that the source code can pass all tests before is deposited to a repository
users
git clone URL
python setup.py test # make sure that the code can pass all the tests
python setup.py install # install the program
or
pip install
Option 2. tox
- configuration, load tox.in, use Python3.9
- packaging, create a source distribution
- environment, create a virtual environment with virtualenv in .tox folder, install packages and dependencies, run commands
- report, print out a report of outcomes for each tox environment
tox.ini
# content of: tox.ini , put in same dir as setup.py
[tox]
envlist = py39
[testenv]
# install pytest in the virtualenv where commands will be executed
deps = pytest
commands =
# NOTE: you can run any command line tool here - not just tests
pytest
developer
tox # implement tests
users
git clone URL
tox # make sure that the code can pass all the tests
python setup.py install # install the program
or
pip install
Unit Test Option 1. Unittest
test fixture, the preparation needed to perform one or more tests
- setUp(), execute before each test method
- tearDown(), execute after each test method
test case, a test case is the smallest unit of testing
- test_*(), all functions starting with "test_"
test suite, a collection of test cases, test suites, or both
- suite = unittest.TestLoader().loadTestsFromTestCase(SimplisticTest);
- suite_2 = unittest.TestLoader().loadTestsFromTestCase(secondTest);
- allTests = unittest.TestSuite([suite, suite_2])
test runner, orchestrates the execution of tests and provides the outcomes to the user
- unittest.TextTestRunner(verbosity=2).run(allTests)
- unittest.main()
import unittest
# import the tested package
class TestClassName(unittest.TestCase):
def setUp():
# define instructions that will be executed before each test method
def tearDown():
# define instructions that will be executed before and after each test method
def test_function():
# function name starts with the letters "test"
test/test_is_prime.py
#!/usr/bin/python
import unittest
from primepackage import is_prime
class Test_is_prime(unittest.TestCase):
def setUp(self):
# Set up database, parameters before each method is tested ...
self.fixture = 10
def tearDown(self):
# Tear down database, parameters after each method is tested ...
del self.fixture
def test_numbers(self):
self.assertEqual(is_prime(2), True)
self.assertEqual(is_prime(8), False)
self.assertEqual(is_prime(1), False)
self.assertEqual(is_prime(83), True)
self.assertEqual(is_prime(self.fixture), False)
def test_raises(self):
with self.assertRaises(ValueError):
is_prime(0)
is_prime(3.14)
is_prime('Hello')
if __name__ == '__main__':
unittest.main()
test/test_suit.py
#!/usr/bin/python
import sys
import unittest
from primepackage import is_prime
class Test_is_prime(unittest.TestCase):
def setUp(self):
# Set up database, parameters before each method is tested ...
self.fixture = 10
def tearDown(self):
# Tear down database, parameters after each method is tested ...
del self.fixture
def test_numbers(self):
self.assertEqual(is_prime(2), True)
self.assertEqual(is_prime(8), False)
self.assertEqual(is_prime(1), False)
self.assertEqual(is_prime(83), True)
self.assertEqual(is_prime(self.fixture), False)
def test_raises(self):
with self.assertRaises(ValueError):
is_prime(0)
is_prime(3.14)
is_prime('Hello')
class Test_more(unittest.TestCase):
def test_numbers(self):
self.assertEqual(is_prime(100), False)
def test_raises(self):
with self.assertRaises(ValueError):
is_prime(-1)
if __name__ == '__main__':
suite_1 = unittest.TestLoader().loadTestsFromTestCase(Test_is_prime);
suite_2 = unittest.TestLoader().loadTestsFromTestCase(Test_more);
allTests = unittest.TestSuite([suite_1, suite_2]);
#unittest.TextTestRunner(verbosity=2).run(allTests);
unittest.main();
# in /Prime folder
python setup.py test
# use test discover to implement multiple test files
# in /src folder
python -m unittest discover ../test "test*.py"
Unit Test Option 2. assert
test/test_assert.py
#!/usr/bin/python
from primepackage import is_prime
def test_numbers():
response = is_prime(1)
assert response == False
response = is_prime(2)
assert response == True
# in /Prime folder
python setup.py test
Unit Test Option 3. Nose
test/test_nose.py
#!/usr/bin/python
from primepackage import is_prime
def test_is_prime():
response = is_prime(5)
assert response == False
setup.py
import setuptools
with open('requirements.txt') as f:
requirements = f.read().splitlines()
setuptools.setup(
test_suite = 'nose.collector',
tests_require=['nose'],
name='linlangleyprime', # a unique name for PyPI
version='0.7',
author='Lin Chen, Yanhua Feng',
author_email='lin.chen@ieee.org, yf@vims.edu',
description='Demo for building a Python project',
long_description=open('README.md').read(),
long_description_content_type="text/markdown",
url='http://lin-chen-langley.github.io',
project_urls = {
'PyPI': 'https://pypi.org/manage/project/linlangleyprime/releases/',
'Conda': 'https://anaconda.org/linchenVA/linlangleyprime'
},
classifiers=[
'Development Status :: 4 - Beta',
'Environment :: X11 Applications :: GTK',
'Intended Audience :: End Users/Desktop',
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU General Public License (GPL)',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python',
'Topic :: Desktop Environment',
'Topic :: Text Processing :: Fonts'
],
install_requires=requirements,
package_dir={'':'src'}, # location to find the packages
packages=setuptools.find_packages(where="src"),
#packages=['primepackage', ], # packages and subpackages containing .py files
python_requires=">=3.9",
scripts=['src/generator',], # the executable files will be installed for user
license='Creative Commons Attribution-Noncommercial-Share Alike license',
)
setup.cfg
[nosetests]
verbosity=1
detailed-errors=1
with-coverage=1
cover-package=nose
debug=nose.loader
# in /Prime folder
python setup.py test
setup_module() | teardown_module(), before and end of the module
with_setup(), before and end of the function
setup() | teardown(), before and end of each function in the class
setup_class() | teardown_class(), before and end of the class
Unit Test Option 4. Doctest
#!/usr/bin/python
def squareTest(x):
"""Return the square of x.
>>> squareTest(2)
4
>>> squareTest(-2)
4
"""
return x*x;
if __name__ == '__main__':
import doctest
doctest.testmod();
python testCode.py -v
Reference