blog/_posts/2018-02-16-how-to-mock-stdo...

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...

A missing blog post image

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 of Popen 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 as stdout attribute

  • Running concerned tests

  • Deleting the temporary file

Everything is more or less explained in this Gist :

Any comment or improvement would be welcome 👌