如何使用子进程有效地测试基于readline的Python程序?

时间:2015-05-14 00:24:40

标签: python unit-testing python-3.x subprocess readline

我有一个Python程序,在某些条件下,应该提示用户输入文件名。但是,我想提供一个默认文件名,用户可以根据需要进行编辑。 这通常意味着他们需要点击退格键来删除当前文件名并将其替换为他们喜欢的文件名。

为此,我已将Python 3的this answer改编为:

def rlinput(prompt, prefill=''):
    readline.set_startup_hook(lambda: readline.insert_text(prefill))
    try:
        return input(prompt)
    finally:
        readline.set_startup_hook()

new_filename = rlinput("What filename do you want?", "foo.txt")

当程序按预期交互运行时 - 按退格并输入新文件名后,new_filename包含bar.txt或用户输入的任何文件名,这可以正常工作。

但是,我还想使用单元测试来测试程序。通常,为此,我将程序作为子进程运行,以便我可以将其输入到stdin(因此在用户使用它时对其进行测试)。我有一些单元测试代码(简化)看起来像这样:

p = Popen(['mypythonutility', 'some', 'arguments'], stdin=PIPE)
p.communicate('\b\b\bbar.txt')

我的意图是这应该模拟用户的退步'超过提供的foo.txt,然后输入bar.txt

然而,这似乎并没有产生预期的效果。相反,经过一些调试后,我的程序中的new_filename最终会显示为\b\b\bbar.txt。我只期待bar.txt

我做错了什么?

1 个答案:

答案 0 :(得分:3)

从Python控制交互式子进程的适当方法是使用pexpect模块。此模块使子进程相信它正在交互式终端会话中运行,并让父进程确切地确定将哪些击键发送到子进程。

  

Pexpect是一个纯Python模块,用于生成子应用程序;控制他们;并回应其产出中的预期模式。 Pexpect就像Don Libes的Expect一样。 Pexpect允许您的脚本生成子应用程序并控制它,就好像人类正在键入命令一样。