Mocking subprocess.Popen depends on import style

When trying to fake Popen, I can only succeed if the subprocess import matches both the unit test code and the main module code.

Given the following module listdir.py:

from subprocess import Popen, PIPE

def listdir(dir):
    cmd = ['ls', dir]
    pc = Popen(cmd, stdout=PIPE, stderr=PIPE)
    out, err = pc.communicate()
    if pc.returncode != 0:
        raise Exception
    return out

      

and after unit test code test_listdir.py

import subprocess
import listdir
import mock

@mock.patch.object(subprocess, 'Popen', autospec=True)
def test_listdir(mock_popen):
    mock_popen.return_value.returncode = 0
    mock_popen.return_value.communicate.return_value = ("output", "Error")
    listdir.listdir("/fake_dir")

      

For some reason Popen is not mocking because the import style is different between the two python modules and running the test always throws an exception.

If I change listdir.py to import all subroutines eg.

import subprocess

def listdir(dir):
    cmd = ['ls', dir]
    pc = subprocess.Popen(cmd, stdout=subprocess.PIPE, 
                          stderr=subprocess.PIPE)
    out, err = pc.communicate()
    if pc.returncode != 0:
        raise ListingErrorException
    return out

      

Then "output" is returned in the test.

Someone wants to shed some light on why, my preference would be to have from the subprocess import Popen, Pipe into both modules, but I just can't figure it out to scoff.

+3


source to share


1 answer


You need to fix the copy of Popen in listdir, not the one you just imported. So instead @mock.patch.object(subprocess, 'Popen', autospec=True)

try@mock.patch.object(listdir, 'Popen', autospec=True)



See this doc for more information: http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch

+6


source







All Articles