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 :
check_output(
['grep', '-E', '3D|VGA|Display'],
stdin=Popen(['lspci'],
stdout=PIPE,
stderr=DEVNULL).stdout
).decode().split(': ')[1].rstrip()So the first thought you might have would be something like :
@mock.patch.object(
'module.submodule.Popen',
'stdout',
'Mocked string',
create=True
)… 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_outputcall needs a readable pipe to work -
stdoutattribute is a runtime attribute ofPopenreturn 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
Popenmock returning this file asstdoutattribute -
Running concerned tests
-
Deleting the temporary file
Everything is more or less explained in this Gist :
Any comment or improvement would be welcome ![]()
