如何模拟缓冲文件句柄以进行单元测试

时间:2015-03-26 11:34:29

标签: python python-2.7

我希望在没有缓冲的情况下正常工作:

$ tail -f logfile | python parser.py

以前我用过:

for line in sys.stdin:
    parse(line)

但现在我已经实施了https://stackoverflow.com/a/18235323/604515

while True:
    line = sys.stdin.readline()
    if not line: break # EOF
    parse(line)

问题:我想不出一种方法可以在没有睡眠的情况下对我的变化进行单元测试()。如何模拟缓冲文件句柄?我可以很容易地模拟stdin,但是它将永远不会缓冲,所以它不会证明什么。

编辑:我看过StringIO,但似乎没有普通文件句柄那样的缓冲行为。

1 个答案:

答案 0 :(得分:1)

首先考虑通过传递来参数化你的函数。您可以使用默认值来sys.stdout。你的方法就是这样的:

def my_reader(feed=sys.stdin):
    while True:
        line = feed.readline()
        if not line:
            break
        parse(line)

现在,您可以通过mock框架和patch parse方法模拟Feed。遗憾的是,您无法直接修补sys.stdin.readline()方法,因为它是一个只读属性。

现在测试中的步骤是:在setUp()中创建stdin的模拟,并在测试中配置它并进行测试。举个例子。

#If you trust parse and you have no other way to test parse instead check its calls you need to patch it
@patch(__name__ + ".parse")
class MyTestCase(unittest.TestCase):
    def setUp(self):
        #Our 'feed'
        self.mock_feed = MagicMock()
        #readline mock
        self.mock_readline = self.mock_feed.readline

    def test_my_reader_empty(self, mock_parse):
        #setting up an empty stream
        self.mock_readline.return_value = ""
        my_reader(self.mock_feed)
        #Our test is that parse was never called
        self.assertFalse(mock_parse.called)

    def test_my_reader_some_lines(self, mock_parse):
        #setting up lines sequence and EOF
        self.mock_readline.side_effect = ["hi,\n", "I'm your standard input\n", "cheers", ""]
        my_reader(self.mock_feed)
        #Call parse with every lines
        mock_parse.assert_has_calls([call("hi,\n"), call("I'm your standard input\n"), call("cheers")])

请注意:我修补了课程,而不是按照文档here修补所有方法。