Stub/Mock-a-Process Module

Say you want to have a test suite that tests logic which runs command-line processes that should *not* be run on the test machine (e.g. they would cause the test machine's configuration to be totally messed up).  You want to test right down to the point where the call is made (i.e. you don't way to say "if testing, don't actually call"), and you would like to test the subprocess.* or os.* calls you're using to call the process.  What do you use?

I haven't found a good mechanism yet (I'm still hopeful about that), so I hacked up something as a starting point for discussion.  The module provides a simple API for creating stub scripts for given executables and a way to inject them into the PATH on test-suite entry and remove them on test-suite exit.  You can provide return-code, stdout and stderr for the called executable to get a generic call-once-and-retrieve value executable, (or you can provide a script to run).import mockproc def setUp( self ): self.processes = mockproc.MockProc() self.processes.append( 'ls', stdout = '''total 20 drwxr-xr-x 2 mcfletch mcfletch 4096 2010-06-05 09:58 . drwxr-xr-x 12 mcfletch mcfletch 4096 2010-06-05 09:58 .. -rw-r--r-- 1 mcfletch mcfletch 3 2010-06-05 09:58 supercali.txt''', stderr='success' ) self.processes.enter() def tearDown( self ): self.processes.exit()

Calls to subprocess.Popen( 'ls' ) within the test-suite will now return the stubbed/mocked value rather than the real command ls. The overriding allows for "pushing" new overrides onto the stack (replacing the on-disk script) so that a single test which needs different values can append a new override and then remove() it to restore the original stub.

You can get the source-code via:

bzr branch lp:mockproc

Mostly I'm wondering if someone else has already published something more robust/featureful so I can kill this little project :) .

Comments

  1. Michael Foord

    Michael Foord on 06/05/2010 1:47 p.m. #

    Hmm... if Mock *isn't* flexible enough to handle mocking processes adequately then I'd like to know how it could be improved.

    http://www.voidspace.org.uk/python/mock/

    :-)

    with @patch('module.subprocess') as mock_subprocess:
    ....

  2. Mike C. Fletcher

    Mike C. Fletcher on 06/05/2010 2:17 p.m. #

    I thought about stubbing out the python call to the process in the current process, but I want something which stubs out the called-process itself, that is, which goes through the real subprocess module. The suite of programs I'm testing may go multiple processes deep in a call (script X calls script Y calls batch Z calls executable A), and I want to mock out executable A for the acceptance/functional tests so that I know the logic for handling a failure in A is correct in X.

  3. Yaniv Aknin

    Yaniv Aknin on 06/06/2010 1:43 a.m. #

    Maybe I'm missing something important here, but why not just write small scripts to mimic whatever dangerous utility you don't want to run?

    i.e., /usr/local/test/bin/evil_binary is a Python script that has the same output as /usr/local/bin/evil_binary, but doesn't do the damage.

    Isn't this better and easier?

  4. Mike C. Fletcher

    Mike C. Fletcher on 06/06/2010 10:07 a.m. #

    That's what the module does (automatically), but on a per-test-run basis, and only for the process being tested (i.e. it doesn't disable ifconfig or shutdown or whatever for your user).

  5. Yaniv Aknin

    Yaniv Aknin on 06/06/2010 5:33 p.m. #

    *blush*

    Oh. :)

Comments are closed.

Pingbacks

Pingbacks are closed.