在Python中模拟标准输出

4 投票
2 回答
4611 浏览
提问于 2025-04-18 11:56

我刚接触Python的单元测试,特别是Mock这个东西。我想知道怎么模拟一个对象,这样我就可以用它做一些操作。我只需要一个不会让循环崩溃的对象,这样我才能完成测试。

for ln in theMock.stdout.readlines()

我试着通过下面的方式来创建一个模拟对象:

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

然后

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

但是它提示说列表对象没有stdout这个属性。

2 个回答

0

这是我提供的一个解决方案,它可以支持使用 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)
4

这样怎么样呢?

from mock import Mock

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

输出结果:

[]

你的 for 循环会被跳过,因为 readlines() 会返回一个空的列表。

撰写回答