4

I am new to Python unit testing, and especially Mock. How would I mock an object that I could do the following with? I just need an object that does not make the loop crash, in order to complete the test.

for ln in theMock.stdout.readlines()

I tried creating a mock by doing

Mock(stdout=Mock(readlines= Lambda: []))

and

Mock(stdout=Mock(spec=file, wraps=StringIO())

but it says that a list object has no attribute stdout.

Daniel Larsson
  • 6,278
  • 5
  • 44
  • 82

2 Answers2

3

How about this?

from mock import Mock

readlines = Mock(return_value=[])
stdout = Mock(readlines=readlines)
theMock = Mock(stdout=stdout)
print(theMock.stdout.readlines())

Output:

[]

Your for loop will just skipped, since readlines() will return an empty list.

dano
  • 91,354
  • 19
  • 222
  • 219
0

My solution that supports stdout.readline() and stdout.readlines():

import os
import subprocess

class MockStdout():
    def __init__(self, output):
        self.output = output.split('\n')
        self.ix = 0

    def readlines(self):
        return '\n'.join(self.output)
      
    def readline(self):
        value = None
        if self.ix < len(self.output):
             value = self.output[self.ix]
             self.ix += 1
        return value
      
class MockSubprocess:
    def __init__(self, output):
        self.stdout = MockStdout(output)

real_popen = getattr(subprocess, 'Popen')
try:
    setattr(subprocess, 'Popen', lambda *args, **kwargs: MockSubprocess('''First Line
Hello
there
from a stranger
standing here
Last Line
''' ))
    cmd = [ 'a_command',
            '--a_switch',
            '--a_parameter=a_value' ]
    listen_subprocess = subprocess.Popen(cmd,
                                         cwd=os.getcwd(),
                                         stdout=subprocess.PIPE,
                                         universal_newlines=True)
    while True:
        line = listen_subprocess.stdout.readline()
        if not line:
            break
        else:
            print(line)

finally:
    setattr(subprocess.Popen, '__call__', real_popen)
Lokiel
  • 1
  • 2