2.1 KiB
title | date | layout | category | image | description |
---|---|---|---|---|---|
How to mock stdout runtime attribute of subprocess.Popen - Python ? | 2018-02-16 | post | Programming | /img/blog/how-to-mock-stdout-runtime-attribute-of-subprocess-popen-python.png | Everything is in the title ! Subprocess library is hard to test... |
After 4 days of struggling and having browsed half of StackOverflow answers, I've decided to publish a blog post accounting for the Python mocking operation described below.
While populating test cases for the archey project, I wanted to mock some subprocess.Popen
calls, used in contexts like this one :
{% highlight python %} check_output( ['grep', '-E', '3D|VGA|Display'], stdin=Popen(['lspci'], stdout=PIPE, stderr=DEVNULL).stdout ).decode().split(': ')[1].rstrip() {% endhighlight %}
So the first thought you might have would be something like :
{% highlight python %} @mock.patch.object( 'module.submodule.Popen', 'stdout', 'Mocked string', create=True ) {% endhighlight %}
... but this does not work, as Popen
expects a file-like object to read from.
In order to sum this mess up, the problems here are :
-
subprocess.check_output
call needs a readable pipe to work -
stdout
attribute is a runtime attribute ofPopen
return object -
The will of not using a different mocking framework than default
unittest
So the final workaround I've come up with is :
-
Mocking the FIFO with a temporary file
-
Writing to this file the mocked content
-
Rewinding to the beginning of the file
-
Make the
Popen
mock returning this file asstdout
attribute -
Running concerned tests
-
Deleting the temporary file
Everything is more or less explained in this Gist :
Any comment or improvement would be welcome 👌