测试 CLI 命令

使用 MockInputOutput

在 4.5.0 版本加入.

MockInputOutput

MockInputOutput 提供了一种简单的方法来编写需要用户输入的命令的测试,例如 CLI::prompt()CLI::wait()CLI::input()

你可以在测试执行期间用 MockInputOutput 替换 InputOutput 类来捕获输入和输出。

备注

当你使用 MockInputOutput 时,你不需要使用 StreamFilterTraitCITestStreamFilterPhpStreamWrapper

辅助方法

getOutput(?int $index = null): string

获取输出。

  • 如果你像 $io->getOutput() 这样调用它,它会返回整个输出字符串。

  • 如果你指定 0 或一个正数,它会返回输出数组项。每个项都有一个 CLI::fwrite() 调用的输出。

  • 如果你指定一个负数 -n,它会返回输出数组的倒数第 n 项。

getOutputs(): array

返回输出数组。每个项都有一个 CLI::fwrite() 调用的输出。

如何使用

  • CLI::setInputOutput() 可以将 MockInputOutput 实例设置到 CLI 类。

  • CLI::resetInputOutput() 重置 CLI 类中的 InputOutput 实例。

  • MockInputOutput::setInputs() 设置用户输入数组。

  • MockInputOutput::getOutput() 获取命令输出。

以下测试代码用于测试命令 spark db:table

<?php

use CodeIgniter\CLI\CLI;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;
use CodeIgniter\Test\Mock\MockInputOutput;

final class DbTableTest extends CIUnitTestCase
{
    use DatabaseTestTrait;

    protected $migrateOnce = true;

    public function testDbTable(): void
    {
        // Set MockInputOutput to CLI.
        $io = new MockInputOutput();
        CLI::setInputOutput($io);

        // User will input "a" (invalid value) and "0".
        $io->setInputs(['a', '0']);

        command('db:table');

        // Get the whole output string.
        $output = $io->getOutput();

        $expected = 'Which table do you want to see? [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]: a';
        $this->assertStringContainsString($expected, $output);

        $expected = 'Data of Table "db_migrations":';
        $this->assertStringContainsString($expected, $output);

        // Remove MockInputOutput.
        CLI::resetInputOutput();
    }
}

不使用 MockInputOutput

测试 CLI 输出

StreamFilterTrait

在 4.3.0 版本加入.

StreamFilterTrait 提供了这些辅助方法的替代方案。

你可能需要测试一些难以测试的东西。有时,捕获一个流,比如 PHP 自己的 STDOUT 或 STDERR,可能会有所帮助。StreamFilterTrait 帮助你捕获所选流的输出。

如何使用
  • StreamFilterTrait::getStreamFilterBuffer() 从缓冲区获取捕获的数据。

  • StreamFilterTrait::resetStreamFilterBuffer() 重置捕获的数据。

在你的一个测试用例中演示这一点的示例:

<?php

namespace Tests;

use CodeIgniter\CLI\CLI;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\StreamFilterTrait;

final class SomeTest extends CIUnitTestCase
{
    use StreamFilterTrait;

    public function testSomeOutput(): void
    {
        CLI::write('first.');

        $this->assertSame("\nfirst.\n", $this->getStreamFilterBuffer());

        $this->resetStreamFilterBuffer();

        CLI::write('second.');

        $this->assertSame("second.\n", $this->getStreamFilterBuffer());
    }
}

StreamFilterTrait 有一个自动调用的配置器。 参见 Testing Traits

如果你在测试中重写了 setUp()tearDown() 方法,那么你必须分别调用 parent::setUp()parent::tearDown() 方法来配置 StreamFilterTrait

CITestStreamFilter

CITestStreamFilter 用于手动/单次使用。

如果你只需要在一个测试中捕获流,那么可以手动向流添加过滤器,而不是使用 StreamFilterTrait trait。

如何使用
  • CITestStreamFilter::registration() 过滤器注册。

  • CITestStreamFilter::addOutputFilter() 向输出流添加过滤器。

  • CITestStreamFilter::addErrorFilter() 向错误流添加过滤器。

  • CITestStreamFilter::removeOutputFilter() 从输出流中移除过滤器。

  • CITestStreamFilter::removeErrorFilter() 从错误流中移除过滤器。

<?php

namespace Tests;

use CodeIgniter\CLI\CLI;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Filters\CITestStreamFilter;

final class SomeTest extends CIUnitTestCase
{
    public function testSomeOutput(): void
    {
        CITestStreamFilter::registration();
        CITestStreamFilter::addOutputFilter();

        CLI::write('first.');

        CITestStreamFilter::removeOutputFilter();
    }
}

测试 CLI 输入

PhpStreamWrapper

在 4.3.0 版本加入.

PhpStreamWrapper 提供了一种方法来编写需要用户输入的方法的测试,例如 CLI::prompt()CLI::wait()CLI::input()

备注

PhpStreamWrapper 是一个流包装类。 如果你不了解 PHP 的流包装器, 请参见 PHP 手册中的 The streamWrapper class

如何使用
  • PhpStreamWrapper::register()PhpStreamWrapper 注册到 php 协议。

  • PhpStreamWrapper::restore() 将 php 协议包装器恢复为 PHP 内置包装器。

  • PhpStreamWrapper::setContent() 设置输入数据。

重要

PhpStreamWrapper 仅用于测试 php://stdin。 但是当你注册它时,它会处理所有 php 协议 流, 例如 php://stdoutphp://stderrphp://memory。 因此强烈建议仅在需要时注册/注销 PhpStreamWrapper。否则,它在注册时会干扰其他内置的 php 流。

在你的一个测试用例中演示这一点的示例:

<?php

namespace Tests;

use CodeIgniter\CLI\CLI;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\PhpStreamWrapper;

final class SomeTest extends CIUnitTestCase
{
    public function testPrompt(): void
    {
        // Register the PhpStreamWrapper.
        PhpStreamWrapper::register();

        // Set the user input to 'red'. It will be provided as `php://stdin` output.
        $expected = 'red';
        PhpStreamWrapper::setContent($expected);

        $output = CLI::prompt('What is your favorite color?');

        $this->assertSame($expected, $output);

        // Restore php protocol wrapper.
        PhpStreamWrapper::restore();
    }
}