我怎样才能模拟python的stdininput?

我试图testing一个函数,从stdin ,我正在testing这样的东西:

 cat /usr/share/dict/words | ./spellchecker.py 

以testing自动化的名义,有什么办法, pyunit可以伪造input到raw_input()

Solutions Collecting From Web of "我怎样才能模拟python的stdininput?"

简短的答案是猴子补丁 raw_input()

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

下面是一个简单的例子,它使用了一个抛出提示符并返回我们想要的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 

更新 – 使用unittest.mock.patch

由于Python 3.3有一个新的子模块unittest称为模拟,正是你所需要做的。 对于那些使用python 2.6或更高版本的用户,可以在这里找到mock的回溯。

 import unittest from unittest.mock import patch import module_under_test class MyTestCase(unittest.TestCase): def setUp(self): # raw_input is untouched before test assert module_under_test.raw_input is __builtins__.raw_input def test_using_with(self): input_data = "123" expected = int(input_data) with patch.object(module_under_test, "raw_input", create=True, return_value=expected): # create=True is needed as raw_input is not in the globals of # module_under_test, but actually found in __builtins__ . actual = module_under_test.function() self.assertEqual(expected, actual) @patch.object(module_under_test, "raw_input", create=True) def test_using_decorator(self, raw_input): raw_input.return_value = input_data = "123" expected = int(input_data) actual = module_under_test.function() self.assertEqual(expected, actual) def tearDown(self): # raw input is restored after test assert module_under_test.raw_input is __builtins__.raw_input if __name__ == "__main__": unittest.main() # where module_under_test.function is: def function(): return int(raw_input("prompt> ")) 

以前的答案 – 替换sys.stdin

我认为sys模块可能是你要找的。

你可以做类似的事情

 import sys # save actual stdin in case we need it again later stdin = sys.stdin sys.stdin = open('simulatedInput.txt','r') # or whatever else you want to provide the input eg. StringIO 

raw_input现在将在被调用时从simulatedInput.txt中读取。 如果simulationInput的内容是

 hello bob 

那么对raw_input的第一个调用将返回“hello”,第二个“bob”和第三个将抛出一个EOFError,因为没有更多的文本要读取。

sys.stdin替换为sys.stdin的一个实例,然后用您希望通过sys.stdin返回的数据加载StringIO实例。 此外, sys.__stdin__包含原始的sys.stdin对象,因此在测试之后恢复sys.stdinsys.stdin = sys.__stdin__一样简单。

Fudge是一个很棒的python mock模块,用这个方便的修饰器来为你做修补,并自动清理。 你应该检查一下。

你没有描述spellchecker.py的代码是什么,这给我自由的推测。

假设是这样的:

 import sys def check_stdin(): # some code that uses sys.stdin 

为了提高check_stdin函数的可测性,我建议像这样重构它:

 def check_stdin(): return check(sys.stdin) def check(input_stream): # same as original code, but instead of # sys.stdin it is written it terms of input_stream. 

现在你的大部分逻辑都在check功能,你可以手工制作你想象得到的任何输入,以便正确测试,而不需要处理stdin

我的2美分。

如果你正在使用模拟模块 (由Michael Foord编写),为了模拟raw_input函数,你可以使用如下语法:

 @patch('src.main.raw_input', create=True, new=MagicMock(return_value='y')) def test_1(self): method_we_try_to_test(); # method or function that calls **raw_input**