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.
For example:
plus_one.py
#!/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...
t_plus_one.py
#!/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()
Output
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