Макет стандартного вывода в Python

#python #unit-testing #mocking #stringio

#python #модульное тестирование #издевательство #stringio

Вопрос:

Я новичок в модульном тестировании Python, и особенно в Mock. Как бы я смоделировал объект, с которым я мог бы сделать следующее? Мне просто нужен объект, который не приводит к сбою цикла, для завершения теста.

 for ln in theMock.stdout.readlines()
  

Я попытался создать макет, выполнив

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

и

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

но там говорится, что у объекта list нет атрибута stdout .

Комментарии:

1. Вы имеете в виду stdin.readlines?

2. Нет, стандартный вывод.readlines() верен.

3. Зачем использовать try для чтения стандартного вывода? Вы хотите знать, что было написано в стандартном выводе?

4. Это не мой код, я просто тестирую его. Но да, это то, что он должен делать.

Ответ №1:

Как насчет этого?

 from mock import Mock

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

Вывод:

 []
  

Ваш for цикл будет просто пропущен, поскольку readlines() вернет пустой список.

Комментарии:

1. Так чисто. Спасибо, теперь я могу идти домой!

2. Поищите в unittest.mock документах sys.stdout , и вы также увидите несколько хороших решений

Ответ №2:

Мое решение, поддерживающее stdout.readline () и 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)