Last active
February 17, 2019 09:57
-
-
Save HorlogeSkynet/5b1378752669cce829d110fd48c4a5c8 to your computer and use it in GitHub Desktop.
How to mock stdout runtime attribute of subprocess.Popen call in Python 3 ?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import os | |
import tempfile | |
import unittest | |
from subprocess import PIPE, Popen, check_output | |
from unittest.mock import patch | |
class YourClass(object): | |
""" | |
This class contains a method in which we might want to mock the `Popen` | |
call and not the `check_output` one. | |
Nevertheless, the pipe uses a `.stdout` runtime attribute expecting a | |
file-like object, so we have to go trough a manual workaround to mock it. | |
Of course, you may want to do the same with `.stderr`, and it's possible ;) | |
""" | |
def __init__(self): | |
self.value = check_output( | |
['grep', '-E', 'regular|mocked'], | |
stdin=Popen(['echo', 'STDOUT (regular)'], | |
stdout=PIPE).stdout # The problem is here. | |
).decode().rstrip() | |
class PopenMock(unittest.TestCase): | |
def setUp(self): | |
# This temporary file will act as a standard stream pipe for `Popen` | |
self.stdout_mock = tempfile.NamedTemporaryFile(delete=False) | |
def tearDown(self): | |
# At the end of the test, we'll close and remove the created file | |
self.stdout_mock.close() | |
os.remove(self.stdout_mock.name) | |
@patch( | |
'__main__.Popen' # Please, take care of "patching" to the right place | |
) | |
def test(self, popen_mock): | |
# We store some data into the fake pipe here | |
self.stdout_mock.write(b'STDOUT (mocked)') | |
# We have to rewind to the beginning of the file for the next reading | |
self.stdout_mock.seek(0) | |
# The fake standard stream attribute is set here | |
popen_mock.return_value.stdout = self.stdout_mock | |
# Run your test(s) ! | |
self.assertEqual(YourClass().value, 'STDOUT (mocked)') | |
if __name__ == '__main__': | |
unittest.main() |
Hey @sandeepkota,
As crazy as it may sound, GitHub has still not implemented a propoer Gists notifications engine, so your comment got lost... Sorry.
I've just tried to run this piece of code against Python2.7(.10), and with the following minor patch applied, it directly worked for me :
--- PopenMock_3.py Sun Feb 17 10:39:14 2019
+++ PopenMock_2.py Sun Feb 17 10:39:56 2019
@@ -1,11 +1,11 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python2
import os
import tempfile
import unittest
from subprocess import PIPE, Popen, check_output
-from unittest.mock import patch
+from mock import patch
class YourClass(object):
Have you fixed this issue since ?
Do you want me to look at your problem precisely ?
With your snippet, it looks like it was related to the passed arguments of Popen
here.
Bye 👋
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In Python 2.7, its throwing the following error.
Could you give an example for 2.7?