Unittesting Python code that uses subprocess.Popen

I have a Python project in which I read external files, process them and write the results to a new file. Input files can be read directly or checked out from the git repository using git show

. The function to call git show

and return stdout looks like this:

def git_show(fname, rev):
    '''Runs git show and returns stdout'''
    process = subprocess.Popen(['git', 'show', '{}:{}'.format(rev, fname)],
                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = process.communicate()
    ret_code = process.wait()
    if ret_code:
        raise Exception(stderr)
    return stdout

      

I have unittests that test all part of the program's processing, that is, everything except reading and writing files. However, I stumbled upon (and fixed) issues regarding encoding the returned string from git_show()

, depending on the Python version and quite possibly the OS and the actual file to read.

I would like to set up unittest git_show()

so that I can make sure the entire application is working, from input to output. However, as far as I know, this is not possible without actually testing the git repository. The whole package is version controlled with git, and I expect if I have a git repository inside a git repository that could lead to problems on its own and a voice in my head tells me that there might not be the best solution anyway.

What is the best way to get the unittesting code that receives input from git show

(and generally, on the command line / Popen.communicate()

)?

+3


source to share


2 answers


Perhaps you want (one of a combination of) different kinds of tests .

Unit tests

Test a small piece of code in code.

  • mock out subprocess.Popen

  • return static values ​​to stdout, stderr

  • check the processing is correct.

The sample code is pretty small, you can only check what is stdout

actually returned and what if nonzero throws wait()

an exception.

Something in between



The vectors to be tested, which are given an input signal, the given output must be created

  • mock out git, instead use cat vector1.txt

    coded in a specific way
  • test result

Integration tests

Check how your code connects to external objects, in this case git

. Such tests protect you from accidentally changing the expectation of the internal system. That is, it "hangs" on the API.

  • create a tarball with a small git repository
  • optionally package git binary into the same tarball
  • unpack tarball
  • execute git command
  • compare the result with the expected
+3


source


So I do it with pytest

Example: (contrived)

from subprocess import Popen, PIPE


def test():
    p = Popen(["echo", "Hello World!"], stdout=PIPE)
    stdout, _ = p.communicate()

    assert stdout == b"Hello World!\n"

      

Output:

$ py.test -x -s test_subprocess.py 
======================================= test session starts ========================================
platform linux2 -- Python 2.7.9 -- py-1.4.28 -- pytest-2.7.1
rootdir: /home/prologic/work/circuits, inifile: 
plugins: cov
collected 1 items 

test_subprocess.py .

===================================== 1 passed in 0.01 seconds =====================================

      




Or using the unittest standard library :

Example:

#!/usr/bin/env python


from unittest import main, TestCase


from subprocess import Popen, PIPE


class TestProcess(TestCase):

    def test(self):
        p = Popen(["echo", "Hello World!"], stdout=PIPE)
        stdout, _ = p.communicate()

        self.assertEquals(stdout, b"Hello World!\n")


if __name__ == "__main__":
    main()

      

Output:

$ python test_subprocess.py 
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

      

0


source







All Articles