0

I am trying to mock a library in Python 2.7 and am running into issues. What I currently have worked but I would like to extend it to be able to differentiate between different subprocess calls. I'd like to do this by reading the second element in my args array, passed into MockedPopen. My issues are that I do not have access to this value when I create the class stdout inside MockedPopen. My method to this point has been to mock out everything up to whmapicall.stdout.read() but I can't seem to pass self into this new class because the value is not yet created.

class MockedPopen:
    PIPE = None
    def __init__(self, args, **kwargs):
        self.args = args
        self.returncode = 0

    def __enter__(self):
        return self

    def __exit__(self, exc_type, value, traceback):
        pass

    @classmethod
    def Popen(self, cmd , **kwargs):
        return self

    class stdout():
        stdout = '''---
data:
  acct:
    -
      bwusage:
        -
          deleted: 0
          domain: hd.tld
          usage: 771853
      deleted: 0
      limit: '88048926720'
      maindomain: hd.tld
      owner: root
      reseller: 0
      totalbytes: 771853
      user: hd
  month: 9
  reseller: root
  totalused: 232307616
  year: 2019
metadata:
  command: showbw
  reason: OK
  result: 1
  version: 1'''

        @classmethod
        def read(self):
            return self.stdout

My test Class

 class TestInit:
     @mock.patch('cpquotafix.subprocess', MockedPopen)
     def testUsername(self):
         user = cpquotafix.User("eddy","cthulhu","hd.tld","root",  None ,"10000")
         assert user.username == "eddy"

The code I want to patch out

def setBandwidthLimit(self):
    whmapicall   = subprocess.Popen(["whmapi1" , "showbw", 'searchtype=user', 'search=^%s$' % self.username], stdout=subprocess.PIPE)
    whmapireturn = whmapicall.stdout.read().split("\n")
def setPackageQuota(self):
    whmapicall   = subprocess.Popen(["whmapi1" , "getpkginfo", "pkg=%s" % self.plan], stdout=subprocess.PIPE)
    whmapireturn = whmapicall.stdout.read().split("\n")
blhsing
  • 91,368
  • 6
  • 71
  • 106
IdecEddy
  • 87
  • 1
  • 16

1 Answers1

0

There is no need for stdout to be a class. You can make stdout a property instead and make it return a Mock object with read attribute defined as a Mock object that, when called, returns the desired string based on the arguments that were passed to the MockedPopen:

class MockedPopen:
    def __init__(self, *args, **kwargs):
        self.args = args

    @property
    def stdout(self):
        return mock.Mock(read=mock.Mock(return_value='''blah blah
metadata:
  command: {}
blah blah'''.format(self.args[1])))
blhsing
  • 91,368
  • 6
  • 71
  • 106
  • My issues are that I want to change the return value based on what is passed into my mock_popen `if self.args[1] == 'showbw':` and `if self.args[1] == 'getpkginfo'` or the first list that is passed into the subprocess.Popen. Ideal I want to return a different data structure based on what kind of API call is made. – IdecEddy Sep 26 '19 at 18:48