【问题标题】:How to mock sys.stdout (err, in) for subprocess.call如何为 subprocess.call 模拟 sys.stdout (err, in)
【发布时间】:2017-07-11 13:22:31
【问题描述】:

我想捕获并分析执行此操作的函数的输出:

subprocess.call(args, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr)

当我在 py.test 下运行此代码而没有任何模拟时,我收到错误:ValueError: redirected Stdin is pseudofile, has no fileno()

当我用 mock 修补 sys.stdin(和其他)时,我得到了同样的错误。

当我使用 mock.mock_open() 修补 sys.stdin 时,我收到错误:AttributeError: Mock object has no attribute 'write'

当我使用 mock.mock_open()('name', 'r') 修补 sys.stdin 时,我收到初始错误:ValueError: redirected Stdin is pseudofile, has no fileno()

有什么方法可以将某种模拟对象作为标准输入/输出传递给子进程吗?

我想要这样的东西:

mocked = (put something here)
subprocess_call('ls', stdin=mocked, stdout=mocked, stderr=mocked)

在 py.test 下运行时应该可以工作。

谢谢。

【问题讨论】:

  • 你为什么不嘲笑subprocess.call?您不是在测试 subprocess 是否有效,只有当使用 subprocess 的代码有效时。
  • 有人可能会争辩说,测试外部命令是否正常工作不是您的工作;你想模拟 subprocess_call 本身。
  • 这个测试是集成测试的一部分,我只模拟 stdout/err 来检查命令结果(因为否则它们会直接进入用户终端)。我需要实际的外部程序输出(来自“args”)来查看我的程序和外部程序都做了他们应该做的事情。
  • 然后将不同的对象分配给sys.stdoutsys.stderr。请务必考虑这些带有文件描述符的必须对象。
  • 谢谢。我可以用模拟创建它们吗?我喜欢稍后检查输出的方式,分配真实文件不是很方便(我需要留意磁盘空间,删除那些文件等)。

标签: python mocking subprocess pytest


【解决方案1】:

经过一番努力,我找到了一种方法来修补和拦截subprocess.call 的标准输出。

我的主要问题是call 函数的非模拟版本需要来自操作系统的实际文件描述符 (FD)。没有任何模拟能够为我提供这样的东西。

同时,我真的很想避免创建任何文件,因为这会使测试的设置/拆卸变得复杂。我决定使用 os.pipe 调用来创建 FD 并将它们用于来自 subprocess.call 的标准输出捕获

这里是我测试的简化版:

def test_exec_results(ssh):
    rfd, wfd = os.pipe()
    w = os.fdopen(wfd, 'w', 0)
    with mock.patch.multiple(app.sys, stdout=w, stderr=w, stdin=None):
        app.myfunction('test message')
    output = os.read(rfd, 1000)
    assert 'test message ' in output
    assert 'some_other_things' in output

【讨论】:

  • app.sys 是什么意思?我怎样才能以一般的方式理解它?
猜你喜欢
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
  • 2019-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-14
  • 1970-01-01
相关资源
最近更新 更多