3

这是一个相当高级的问题,也许了解这个问题可能不需要 Symfony 和 Behat 的知识。

因此,为了测试bin/albumgrab我使用 Symfony 控制台组件用 PHP 编写的交互式 CLI 应用程序的输入和输出,我设置了 Behat 功能上下文来构建一个expect脚本,通过exec.

exec命令通过 Symfony 在 PHP 中运行Process

$expect = <<<BASH
exec expect -c '
    set timeout 180
    spawn bin/albumgrab
    expect "Please enter the name of the directory"
    send "/tmp/php-london\n"
    expect "Please enter the URL to the first image"
    send "https://www.facebook.com/PeeHPLondon/photos/pb.7119218495.-2207520000.1430669248./10153559172718496/?type=3&src=https%3A%2F%2Ffbcdn-sphotos-g-a.akamaihd.net%2Fhphotos-ak-xfp1%2Fv%2Ft1.0-9%2F10986697_10153559172718496_5727444485530442900_n.jpg%3Foh%3Dc47770f4cd15fecc6888bcd504899087%26oe%3D55DA9CB0%26__gda__%3D1439174101_7c78a93bf247dbad6c56681b6db5309c&size=960%2C959&fbid=10153559172718496\\n"
    interact
'

BASH;

$process = new Symfony\Component\Process\Process($expect);

$process->mustRun();

但是,当它通过第二个输入时,它似乎退出但成功。

来电:

$process->setTty(true);

让它一直运行,但会直接打印到标准输出,我不能再捕获输出来做出断言,即使使用 PHP 的输出缓冲也是如此。

无论如何,我认为 PTY 会更合适:

$process->setPty(true);

因为它是这个 StackOverflow 问题的解决方案。但是,并非所有地方都支持此功能,至少在 Mac OS X 上不支持。

您可以在 Github 中看到我迄今为止所做的尝试:https ://github.com/adamelso/albumgrab/pull/13/files和最后一次尝试的 Travis 输出https://travis-ci.org/adamelso/专辑抓取/工作/61137499

所以我的主要问题是为什么它一直以 0 提前退出以及如何防止它?

4

2 回答 2

1

为了能够收到问题的答案 - 您肯定需要终端 (TTY) 或伪终端 (PTY) 来获取任何用户输入。

这就是为什么 - 没有$process->setTty(true)setPty(true)- QuestionHelper默默地回退到默认值并且命令成功并退出代码 0。

现在——用示例用户输入来测试你的命令——你应该使用 symfony 的控制台帮助组件而不是使用 expect。

Symfony\Component\Console\Helper\HelperSet 
Symfony\Component\Console\Tester\CommandTester

如何使用这些帮助器在手册章节测试需要输入的命令中进行了描述。

于 2015-05-04T13:04:49.227 回答
1

根据期望脚本等待命令挂起的答案,您需要等待 EOF 而不是使用interact命令:

set timeout 180
spawn ./bin/albumgrab
expect "Please enter the name of the directory"
send "/tmp/php-london\n"
expect "Please enter the URL to the first image"
send "https://www.facebook.com/PeeHPLondon/photos/pb.7119218495.-2207520000.1430669248./10153559172718496/\n"
expect EOF

这是我用来在 OS X 上测试它的完整脚本:

<?php

require_once __DIR__.'/vendor/autoload.php';

use Symfony\Component\Process\Process;

$expect = <<<BASH
exec expect -c '
    set timeout 180
    spawn ./bin/albumgrab
    expect "Please enter the name of the directory"
    send "/tmp/php-london\n"
    expect "Please enter the URL to the first image"
    send "https://www.facebook.com/PeeHPLondon/photos/pb.7119218495.-2207520000.1430669248./10153559172718496/?type=3&src=https%3A%2F%2Ffbcdn-sphotos-g-a.akamaihd.net%2Fhphotos-ak-xfp1%2Fv%2Ft1.0-9%2F10986697_10153559172718496_5727444485530442900_n.jpg%3Foh%3Dc47770f4cd15fecc6888bcd504899087%26oe%3D55DA9CB0%26__gda__%3D1439174101_7c78a93bf247dbad6c56681b6db5309c&size=960%2C959&fbid=10153559172718496\\n"
    expect EOF
'

BASH;

$process = new Process($expect);
$process->setPty(true);
$process->start();

$process->wait(function ($type, $buffer) {
    if (Process::ERR === $type) {
        echo 'ERR > '.$buffer;
    } else {
        echo 'OUT > '.$buffer;
    }
});

if (!$process->isSuccessful()) {
    throw new \RuntimeException($process->getErrorOutput());
}
于 2015-05-07T15:18:09.233 回答