The PyTest documentation states that stdin is redirected to null as no-one will want to do interactive testing in a batch test context. This is true, but interactive is not the only use of stdin. I want to test code that uses stdin just as it would use any other file. I am happy with stdout and sterr being captured but how to actually have stdin connected to an io.StringIO object say in a PyTest conformant way?
Asked
Active
Viewed 9,174 times
42
-
1Just mock stdin in those tests. – Antti Haapala -- Слава Україні Aug 02 '16 at 14:25
-
1You've almost answered your own question. You could refactor your code to use something like `io.StringIO` instead of referencing stdin directly, in order to pass a mocked object during testing while being able to handle stdin during "real" usage. – Two-Bit Alchemist Aug 02 '16 at 14:26
-
1See for example http://stackoverflow.com/questions/13238566/python-equivalent-of-input-using-sys-stdin – Antti Haapala -- Слава Україні Aug 02 '16 at 14:26
-
I tried: `def test_main_with_empty_list_argument(): with patch(sys.stdin, io.StringIO('')): wc.main([])` but it gives: `E AttributeError: 'DontReadFromInput' object has no attribute 'rsplit'` – Russel Winder Aug 02 '16 at 14:51
-
OK, stupid error, I failed to put the sys.stdin as a string. :-( – Russel Winder Aug 02 '16 at 15:53
2 Answers
48
You can monkeypatch it:
def test_method(monkeypatch):
monkeypatch.setattr('sys.stdin', io.StringIO('my input'))
# test code

OrangeDog
- 36,653
- 12
- 122
- 207
2
Maybe you could run your script as a subprocess
? In Python 3.6:
import subprocess
def test_a_repl_session():
comlist = ['./executable_script.py']
script = b'input\nlines\n\n'
res = subprocess.run(comlist, input=script,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
assert res.returncode == 0
assert res.stdout
assert res.stderr == b''

xealits
- 4,224
- 4
- 27
- 36
-
1This works and was what I was doing for awhile until I needed coverage reports. Nothing in the subprocess counts for that. :( – brian d foy Dec 24 '22 at 13:25