测试 CLI 命令

使用 MockInputOutput

Added in version 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

Added in version 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 包含一个会自动调用的配置方法。 详见 测试 Trait

如果测试中重写了 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

Added in version 4.3.0.

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

备注

PhpStreamWrapper 是一个流封装类。 如果不了解 PHP 的流封装,请参阅 PHP 手册中的 streamWrapper 类

使用方法
  • 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();
    }
}