First of all consider to parameterize your function by pass the stream. You can use default to take sys.stdout
. Your method become something like that:
def my_reader(feed=sys.stdin):
while True:
line = feed.readline()
if not line:
break
parse(line)
Now you can mock your feed by mock
framework and patch
your parse
method. Unfortunately you cannot patch directly sys.stdin.readline()
method because is a read only attribute.
Now the steps in your test are: create a mock of stdin in setUp()
and in your tests configure the it and do your test. Follow an example.
#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")])
Just a note: I patched the class instead patching all method as documented here.