我希望它在没有缓冲的情况下正常工作:
$ 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,但它似乎不像普通的文件句柄那样具有缓冲行为。
首先考虑通过传递流来参数化函数。您可以使用默认值来获取sys.stdout
。你的方法变成了这样:
def my_reader(feed=sys.stdin):
while True:
line = feed.readline()
if not line:
break
parse(line)
现在您可以通过mock
框架和patch
的parse
方法来模拟您的提要。不幸的是,您无法直接修补sys.stdin.readline()
方法,因为它是只读属性。
现在测试中的步骤是:在setUp()
中创建stdin的mock,并在测试中配置它并进行测试。举个例子。
#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 inputn", "cheers", ""]
my_reader(self.mock_feed)
#Call parse with every lines
mock_parse.assert_has_calls([call("hi,n"), call("I'm your standard inputn"), call("cheers")])
只需注意:我修补了类,而不是修补了此处所述的所有方法。