如何用鼻子测试命令行脚本?

时间:2013-06-04 11:40:49

标签: python unit-testing nose python-unittest

我在'bin'目录中创建了一个带有一些命令行脚本的Python库(这样setup.py会在用pip安装它时将它安装到'bin'中。由于这不是Python模块,我无法弄清楚如何用鼻子测试它。

如何使用nose / unittest测试属于库的命令行脚本?

1 个答案:

答案 0 :(得分:11)

在脚本中使用“if __name__ == "__main__":”惯用法,并在 function -s中封装所有 function -ality。

然后你可以将你的脚本import转换成另一个脚本(例如单元测试脚本),而不需要执行它的主体。这将允许您编写功能的单元测试并通过nose运行它们。

我建议将“主”块保持一两行。

例如:

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))

您可以在单元测试中测试命令行参数,输出,异常和返回代码......

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()

输出

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