6

我有一个 python 模块/脚本,它可以完成其中的一些

  1. 在脚本内的各种嵌套级别,我接受命令行输入,验证它们,应用合理的默认值
  2. 我还检查是否存在一些目录

以上只是两个例子。我试图找出测试这一点的最佳“策略”。我所做的是我在模块周围raw_input和模块中构建了包装函数os.path.exists,然后在我的测试中我覆盖这两个函数以从我的数组列表中获取输入或执行一些模拟行为。这种方法有以下缺点

  1. 包装函数只是为了测试而存在,这会污染代码
  2. 我必须记住每次都在代码中使用包装函数,而不仅仅是调用os.path.existsraw_input

有什么绝妙的建议吗?

4

3 回答 3

3

解决方案1:我会做这样的事情,因为它有效:

def setUp(self):
    self._os_path_exists = os.path.exists
    os.path.exists = self.myTestExists # mock

def tearDown(self):
    os.path.exists = self._os_path_exists

这不是很好。

解决方案2:重组代码不是您所说的选项,对吧?这会使理解和不直观变得更糟。

于 2013-02-19T12:50:01.573 回答
3

Johnnysweb 可以满足您的需要,但您可以导入和使用mock ,而不是自己滚动。Mock 是专门为单元测试而设计的,它让你想要做的事情变得非常简单。它内置于 Python 3.3。

例如,如果要运行替换 os.path.isfile 并始终返回 True 的单元测试:

try:
    from unittest.mock import patch
except ImportError:
    from mock import patch

class SomeTest(TestCase):

    def test_blah():
        with patch("os.path.isfile", lambda x: True):
            self.assertTrue(some_function("input"))

这可以为您节省大量样板代码,而且可读性很强。

如果你需要一些更复杂的东西,例如,替换 supbroccess.check_output,你可以创建一个简单的辅助函数:

def _my_monkeypatch_function(li):
     x,y = li[0], li[1]
     if x == "Reavers":
        return "Gorram"
     if x == "Inora":
        return "Shiny!"
     if x == y:
        return "The Ballad of Jayne"

def test_monkey():
     with patch("subprocess.check_output", _my_monkeypatch_function):
            assertEquals(subprocess.check_output(["Mudder","Mudder"]),
                                                 "The Ballad of Jayne")
于 2013-12-30T20:16:26.743 回答
3

简短的回答是猴子修补这些系统调用。

如何在 Python 中显示重定向的标准输入的答案中有一些很好的例子?

这是一个raw_input()使用 a的简单示例,lambda它会丢弃提示并返回我们想要的内容。

被测系统

$ cat ./name_getter.py
#!/usr/bin/env python

class NameGetter(object):

    def get_name(self):
        self.name = raw_input('What is your name? ')

    def greet(self):
        print 'Hello, ', self.name, '!'

    def run(self):
        self.get_name()
        self.greet()

if __name__ == '__main__':
    ng = NameGetter()
    ng.run()

$ echo Derek | ./name_getter.py 
What is your name? Hello,  Derek !

测试用例:

$ cat ./t_name_getter.py
#!/usr/bin/env python

import unittest
import name_getter

class TestNameGetter(unittest.TestCase):

    def test_get_alice(self):
        name_getter.raw_input = lambda _: 'Alice'
        ng = name_getter.NameGetter()
        ng.get_name()
        self.assertEquals(ng.name, 'Alice')

    def test_get_bob(self):
        name_getter.raw_input = lambda _: 'Bob'
        ng = name_getter.NameGetter()
        ng.get_name()
        self.assertEquals(ng.name, 'Bob')

if __name__ == '__main__':
    unittest.main()

$ ./t_name_getter.py -v
test_get_alice (__main__.TestNameGetter) ... ok
test_get_bob (__main__.TestNameGetter) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
于 2013-02-19T13:12:12.493 回答