I have a program that uses the Python fileinput module, and I am trying to write unittests for the main() function. They work find when using an actual file, but raise OSError: reading from stdin while output is captured when I try to pass data via stdin. What is the correct way to mock the stdin input when using fileinput?
Example my_fileinput.py:
"""
$ echo "42" | python3.8 my_fileinput.py -
answer: 42
"""
import fileinput
import sys
def main():
for line in fileinput.input(sys.argv[1:]):
sys.stdout.write(f"answer #{fileinput.lineno()}: {line}")
if __name__ == "__main__":
main()
Example test_my_fileinput.py:
"""
$ python3.10 -m pytest test_my_fileinput.py
OSError: reading from stdin while output is captured
"""
import io
from unittest import mock
import my_fileinput
def test_stdin():
"""Test fileinput with stdin."""
with mock.patch.object(my_fileinput, "raw_input", create=True, return_value="42"):
with mock.patch("sys.stdout", new=io.StringIO()) as stdout:
with mock.patch("sys.argv", ["my_fileinput.py", "-"]):
# Raises OSError: reading from stdin while output is captured
my_fileinput.main()
assert stdout.getvalue() == "answer #1: 42"
I have tried various ways of mocking stdin, all with the same results. All result in the same OSError.
fileinput.inputworks correctly? Your test need only ensure that whateverfileinput.inputreturns is iterated over correctly. I would just mock the function itself to provide a sufficient iterable for testing.fileinputsuch asfileinput.lineno(). andfileinput.isstdin().fileinputdoes is not as important as how your code uses what it produces."answer #1: 42"now that you have modified the code under test? Where did the #lineno go? The usage example in the docstring doesn't match the behavior of your code anymore.