【问题标题】:How to test command line scripts with nose?如何用鼻子测试命令行脚本?
【发布时间】:2013-05-30 19:01:36
【问题描述】:

我在“bin”目录中创建了一个带有一些命令行脚本的 Python 库(这样setup.py 将在使用pip 安装它时将其安装到“bin”中)。由于这不是 Python 模块,我不知道如何用鼻子测试它。

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

【问题讨论】:

    标签: python unit-testing nose python-unittest


    【解决方案1】:

    在您的脚本中使用“if __name__ == "__main__":”习语,并在function-s 中封装所有 function-ality。 p>

    然后您可以将您的脚本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
    

    【讨论】:

    • 这就是我所做的。我的 CLI 脚本基本上只处理异常和 arg 解析并调用库模块。我仍然想确保如果有错误,它返回一个代码 1,否则返回一个 0,类似的事情。
    • 没有。函数会引发错误。如果出现任何错误,则需要对其进行处理,然后脚本会返回一个非零返回码。如果没有发生错误,则脚本返回零。能够测试命令行参数也很有用。该库已经过全面测试(100% 覆盖率),似乎 CLI 脚本也应该进行测试。
    • @user1491250:听起来您仍然可以从“主”块中提取更多内容。我在答案中添加了示例,以演示如何在单元测试中测试命令行参数、输出、异常和返回代码。
    猜你喜欢
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-02
    • 1970-01-01
    • 1970-01-01
    • 2015-08-21
    • 1970-01-01
    相关资源
    最近更新 更多