kartavik/php-mock

PHP-Mock 可以模拟内置的 PHP 函数(例如 time())。PHP-Mock 依赖于 PHP 的命名空间回退策略。无需进一步扩展。

3.0.1 2019-02-18 12:24 UTC

This package is auto-updated.

Last update: 2024-09-19 01:16:11 UTC


README

Build Status codecov

PHP-Mock 是一个测试库,可以模拟非确定的内置 PHP 函数,如 time()rand()。这是通过 PHP 的命名空间回退策略 实现的

如果存在一个命名空间函数 [...],PHP 将回退到全局函数 [...]。

PHP-Mock 通过提供命名空间函数来利用此功能。即您必须在 非全局命名空间 上下文中以 未指定名称 调用该函数

namespace foo;

$time = time(); // This call can be mocked, a call to \time() can't.

需求和限制

  • 只有命名空间上下文中的 未指定名称 函数调用可以被模拟。例如,在命名空间 foo 中对 time() 的调用是可模拟的,而对 \time() 的调用则不是。

  • 必须在测试类中对未指定名称的函数第一次调用之前定义模拟。这在 Bug #68541 中有记录。在大多数情况下,您可以忽略此限制,但如果您遇到此问题,可以在第一次调用之前调用 Mock::define()。这将定义一个无副作用的命名空间函数,稍后可以启用。另一种有效的方法是在隔离进程中运行您的测试。

替代方案

如果您无法依赖或只是不想使用命名空间回退策略,有其他技术可以模拟内置 PHP 函数

  • PHPBuiltinMock 依赖于 APD 扩展。

  • MockFunction 是一个 PHPUnit 扩展。它使用 runkit 扩展。

  • UOPZ 是一个允许(例如)重命名和删除函数的 Zend 扩展。

  • vfsStream 是一个虚拟文件系统的流包装器。这可以帮助您编写覆盖 PHP 流函数(例如 fread()readdir())的测试。

安装

使用 Composer

composer require --dev kartavik/php-mock

用法

您不需要学习另一个 API。PHP-Mock 与这些测试框架集成了

注意:如果您计划使用上述提到的任何测试框架,您可以跳过阅读任何其他内容,直接转到特定的集成项目。

PHP-Mock API

创建一个 Mock 对象。您可以使用 MockBuilder 的流畅 API 来完成此操作

  • MockBuilder::setNamespace() 设置被模拟函数的目标命名空间。

  • MockBuilder::setName() 设置被模拟函数的名称(例如 time())。

  • MockBuilder::setFunction() 设置具体的模拟实现。

  • MockBuilder::setFunctionProvider() 相对于 MockBuilder::setFunction(),设置模拟实现为 FunctionProvider

    • FixedValueFunction 是一个简单的实现,它始终返回相同的值。

    *FixedMicrotime 是一个简单的实现,它始终返回相同的微时间戳。此类与 FixedValueFunction 不同,因为它包含 microtime() 的浮点数和字符串格式的转换器。

    • FixedDate 是一个简单的实现,它始终返回固定时间戳的格式化日期。

    • SleepFunction 是一个 sleep() 实现,它不会停止程序,而是增加一个 Increment,例如一个 time() 模拟。

    • UsleepFunction 是一个 usleep() 实现,它不会停止程序,而是增加一个 Increment,例如一个 microtime() 模拟。

  • MockBuilder::build() 构建 Mock 对象。

构建完 Mock 对象后,您必须调用 enable() 来在给定的命名空间中启用模拟。完成模拟后,您应通过在模拟实例上调用 disable() 来禁用它。

此示例说明了在命名空间 foo 中对无限定函数 time() 进行模拟。

namespace foo;

use phpmock\MockBuilder;

$builder = new MockBuilder();
$builder->setNamespace(__NAMESPACE__)
    ->setName("time")
    ->setFunction(
        function () {
            return 1417011228;
        }
    );
                    
$mock = $builder->build();

// The mock is not enabled yet.
assert (time() != 1417011228);

$mock->enable();
assert (time() == 1417011228);

// The mock is disabled and PHP's built-in time() is called.
$mock->disable();
assert (time() != 1417011228);

您可以使用现有的 FixedValue 而不是使用 MockBuilder::setFunction() 来设置模拟函数。

namespace foo;

use Kartavik\PHPMock\MockBuilder;
use Kartavik\PHPMock\Functions\FixedValue;

$builder = new MockBuilder();
$builder->setNamespace(__NAMESPACE__)
    ->setName("time")
    ->setFunctionProvider(new FixedValueFunction(1417011228));

$mock = $builder->build();

重置全局状态

启用的模拟会改变全局状态。如果后续测试运行了会无意中调用模拟的代码,这会破坏测试。因此,您应在测试用例后始终禁用模拟。您将必须禁用创建的模拟。您可以通过调用静态方法 Mock::disableAll() 为所有模拟执行此操作。

模拟环境

可以将几个模拟函数的复杂模拟环境分组在 Environment\Mock 中。

  • Environment\Mock::enable() 启用此环境中所有模拟的函数。

  • Environment\Mock::disable() 禁用此环境中所有模拟的函数。

  • Environment\Mock::define() 定义此环境中所有模拟的函数。

SleepEnvironmentBuilder

Environment\SleepBuilder 构建一个模拟环境,其中 sleep()usleep() 立即返回。此外,它们会增加模拟的 date()time()microtime() 中的时间量。

namespace foo;

use Kartavik\Environment\SleepBuilder;

$builder = new SleepEnvironmentBuilder();
$builder->addNamespace(__NAMESPACE__)
    ->setTimestamp(1417011228);

$environment = $builder->build();
$environment->enable();

// This won't delay the test for 10 seconds, but increase time().        
sleep(10);

assert(1417011228 + 10 == time());

如果模拟函数应在不同的命名空间中,您可以使用 Environment\SleepBuilder::addNamespace() 添加更多命名空间。

作者和贡献者

Fork 贡献者 - Roman Vakura

作者 - 此项目是 php-mock/php-mock 的分支。

许可证