我希望在没有缓冲的情况下正常工作:
$ 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,但似乎没有普通文件句柄那样的缓冲行为。
答案 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修补所有方法。