我想测试一个执行 shell 命令的 Python 函数。
根据testfixtures有两种方法:
我的函数称为
run_in_shell
。尽管 subprocess 模块是实现它的明显方法,但我的函数没有明确依赖它,所以我试图进行“真正的”测试。
import subprocess
def run_in_shell(command, shell_name=None):
"""Run command in default shell. Use named shell instead if given."""
subprocess.run(command, shell=True, executable=shell_name)
此测试表明该函数可以使用默认 shell 执行命令。
import pytest
def test_with_command_string(capfd):
run_in_shell("echo 'hello'")
cap = capfd.readouterr()
assert cap.out.strip() == "hello"
assert cap.err.strip() == ""
我还想表明它可以在用户选择的 shell 中执行,例如
/bin/bash
。
调用非常简单。这会将
hello
打印到终端。
run_in_shell("echo 'hello'", shell_name="/bin/bash")
在没有嘲笑的情况下,我如何表明它执行了
/bin/bash
来这样做?
我尝试使用 ptracer 来跟踪系统调用,但输出令我失望。
def callback(syscall):
name = syscall.name
args = ",".join([str(a.value) for a in syscall.args])
print(f"{name}({args})")
with ptracer.context(callback):
run_in_shell("echo 'hello'")
with ptracer.context(callback):
run_in_shell("echo 'hello'", shell_name="/bin/bash")
我希望看到带有 shell 名称的
clone
或 fork
调用,但没有什么那么清楚。我不明白 read
调用中的字符串,也没有看到任何 write
调用。
hello
pipe2((23, 24),524288)
clone(18874385,0,None,261939,0)
close(24)
read(23,bytearray(b'U\r\r\n'),50000)
close(23)
wait4(262130,0,0,None)
hello
pipe2((24, 25),524288)
clone(18874385,0,None,261939,0)
futex(2,129,1,0,9693984,9694016)
futex(0,129,1,0,None,9694016)
close(25)
read(24,bytearray(b'\x1d'),50000)
close(24)
wait4(262308,0,0,None)
此时此刻我已经力不从心了。我肯定误解了系统调用的真正作用。我错过了什么?
使用 Python 和 PyTest 进行测试是否可能且实用?如果没有,我将重新定义我的函数以显式依赖于子流程函数之一,然后我可以使用模拟来测试它是否向函数发送了正确的消息。
如果我理解正确的话,对于此检查,我们要做的就是验证传入的任何 shell 是否正在使用。
我会尽可能简单,只打印活动 shell 的名称,然后验证它是否与目标 shell 匹配。类似的东西
def test_executes_in_specified_shell(capfd):
target_shell = "/bin/bash"
print_current_shell = "ps -p $$ -oargs="
run_in_shell(print_current_shell, shell_name=target_shell)
current_shell = # Retrieve/parse capfd stdout
assert current_shell == target_shell