robier / mock-global-php-functions

模拟全局命名空间中存在的任何函数

v1.0.1 2023-01-01 23:17 UTC

This package is auto-updated.

Last update: 2024-08-30 01:32:29 UTC


README

Build Status MIT

模拟全局PHP函数

此库允许您模拟任何全局PHP函数以返回预定义的值。

在看到Symfony的ClockMock组件后,我创建了此库,该组件用于模拟与时间相关的PHP原生函数。我对如何模拟任何PHP全局函数感到好奇,因此创建了此小型库。

这是通过PHP的命名空间回退策略实现的。

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

库使用所述功能动态创建命名空间函数。为了使此库正常工作,您正在测试的代码应在非全局命名空间上下文中,并调用未指定名称的函数。例如

namespace foo;

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

已知限制

  • 只有命名空间上下文中的未指定名称的函数调用可以模拟。例如,在命名空间foo中对time()的调用是可模拟的,而对\time()的调用则不是。
  • 必须在测试类中对未指定名称的函数的第一个调用之前定义模拟。这在问题编号68541中有记录。在大多数情况下,您可以忽略此限制,因为您只需要在测试之前定义模拟。还建议您将测试作为独立进程运行。

API

目前有2个模拟对象可供开发者使用

  • MockFunction - 使用您自己的匿名函数模拟任何给定函数
  • FreezeClock - 模拟与时间/休眠/日期相关的函数,以便它们保持同步

MockFunction

可以模拟全局命名空间中任何函数的对象。只要不调用该模拟的魔法方法__destruct,或者通过disable方法手动禁用,模拟就是活动的。这样,在编写测试时,您不需要手动关闭模拟,因为一旦当前作用域存在,模拟就会禁用,并且您可以有一个干净的开始。

注意:在创建模拟时,请使用静态回调而不是常规回调。这防止它们自动绑定到当前类。

示例

// mock is active as soon it's defined
$mock = new MockFunction('app', 'rand', static function(){
    return 5;
});

namespace app {
    // some logic
    $randomNumber = rand(); // random number will be always 5
    // some logic
}

模拟sleep函数的示例

$mock = new MockFunction('app', 'sleep', static function(){
    return 0;
});

namespace app {
    // some logic
    sleep(100); // sleep will not wait for 100 seconds as function is mocked
    // some logic
}

FreezeClock

可以在给定命名空间中冻结时间的手动对象。

方便的工厂方法

  • atZero - 停止时间在时间戳0
  • atTime - 停止在提供的时间
  • atMicrotime - 停止在提供的微时间
  • atNow - 停止在当前时间

受影响的函数

  • date - 返回冻结格式的时间
  • time - 返回冻结时间
  • microtime - 返回冻结微时间
  • sleep - 增加冻结时间,并且它不像常规sleep函数那样阻塞
  • usleep - 增加冻结时间,并且它不像常规usleep函数那样阻塞
use Robier\MockGlobalFunction\FreezeClock;

$mock = new FreezeClock::atZero('app/testNamespace');

\app\testNamespace\sleep(15);

\app\testNamespace\time(); // would return 15
\app\testNamespace\microtime(true); // would return 15.0 also

测试

首先运行docker/build构建容器,然后运行docker/run composer run test以运行所有测试。

贡献

欢迎您贡献!