I've created a Python library with some command-line scripts in a 'bin' directory (so that setup.py
will install it into 'bin' when installing it with pip
). Since this isn't a Python module, I can't work out how to test it with nose.
How can I test a command line script that's part of a library using nose
/unittest
?
nose can be integrated with DocTest by using with-doctest option in athe bove command line. The result will be true if the test run is successful, or false if it fails or raises an uncaught exception. nose supports fixtures (setup and teardown methods) at the package, module, class, and test level.
Nose is a popular test automation framework in Python that extends unittest to make testing easier. The other advantages of using the Nose framework are the enablement of auto discovery of test cases and documentation collection.
pytest is capable of discovering and running tests written in unittest and nose. State true or false.
Use the "if __name__ == "__main__":
" idiom in your scripts and encapsulate all of the function-ality in function-s.
Then you can import
your scripts into another script (such as a unit test script) without the body of it being executed. This will allow you to write unit-tests for the functionality and run them through nose
.
I recommend keeping the "main" block to a line or two.
#!/usr/bin/env python
import sys
def main(args):
try:
output(plus_one(get_number(args)))
except (IndexError, ValueError), e:
print e
return 1
return 0
def get_number(args):
return int(args[1])
def plus_one(number):
return number + 1
def output(some_text):
print some_text
if __name__ == '__main__':
sys.exit(main(sys.argv))
You can test command-line parameters, output, exceptions and return codes in your unittests...
#!/usr/bin/env python
from StringIO import StringIO
import plus_one
import unittest
class TestPlusOne(unittest.TestCase):
def test_main_returns_zero_on_success(self):
self.assertEquals(plus_one.main(['test', '1']), 0)
def test_main_returns_nonzero_on_error(self):
self.assertNotEqual(plus_one.main(['test']), 0)
def test_get_number_returns_second_list_element_as_integer(self):
self.assertEquals(plus_one.get_number(['anything', 42]), 42)
def test_get_number_raises_value_error_with_string(self):
self.assertRaises(ValueError, plus_one.get_number, ['something',
'forty-two'])
def test_get_number_raises_index_error_with_too_few_arguments(self):
self.assertRaises(IndexError, plus_one.get_number, ['nothing'])
def test_plus_one_adds_one_to_number(self):
self.assertEquals(plus_one.plus_one(1), 2)
def test_output_prints_input(self):
saved_stdout, plus_one.sys.stdout = plus_one.sys.stdout, StringIO('_')
plus_one.output('some_text')
self.assertEquals(plus_one.sys.stdout.getvalue(), 'some_text\n')
plus_one.sys.stdout = saved_stdout
if __name__ == '__main__':
unittest.main()
python plus_one.py 41
42
nosetests -v t_plus_one.py
test_get_number_raises_index_error_with_too_few_arguments (t_plus_one.TestPlusOne) ... ok
test_get_number_raises_value_error_with_string (t_plus_one.TestPlusOne) ... ok
test_get_number_returns_second_list_element_as_integer (t_plus_one.TestPlusOne) ... ok
test_main_returns_nonzero_on_error (t_plus_one.TestPlusOne) ... ok
test_main_returns_zero_on_success (t_plus_one.TestPlusOne) ... ok
test_output_prints_input (t_plus_one.TestPlusOne) ... ok
test_plus_one_adds_one_to_number (t_plus_one.TestPlusOne) ... ok
----------------------------------------------------------------------
Ran 7 tests in 0.002s
OK
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With