jeremeamia/func-mocker

允许您覆盖命名空间内使用的全局函数,以进行测试目的。

0.1.0 2016-03-15 04:25 UTC

This package is auto-updated.

Last update: 2024-09-20 11:53:42 UTC


README

FuncMocker – 像朋克摇滚一样模拟PHP函数?

Latest Version on Packagist Software License Build Status Total Downloads

允许您覆盖(即模拟)在特定命名空间内使用的全局函数,以进行测试。

我为以下两个主要用例开发了此功能

  1. 当您正在测试调用非确定性函数的对象(如time()rand()),并且需要这些函数返回确定性值以进行测试时。
  2. 当您正在处理必须调用函数的对象的代码。这在以前不是面向对象的遗留代码库中很常见。例如,如果您的项目中有一个名为db_add()的函数,您最终在模型层中使用该对象,您可能希望在测试时“模拟”该函数,以便您实际上不需要在单元测试中调用数据库。

此代码背后的简单技术在此Fabian Schmengler的博客文章中进行了描述。基本上,它涉及利用PHP的命名空间解析规则

安装

通过Composer

$ composer require jeremeamia/func-mocker

用法

假设您有一个在命名空间My\App中定义的RandomNumberGenerator类,它调用全局函数rand()。您可以使用FuncMocker覆盖该特定命名空间中rand()的使用。

use My\App\RandomNumberGenerator;
use FuncMocker\Mocker;

Mocker::mock('rand', 'My\App', function () {
    return 5;
});

$rng = new RandomNumberGenerator(1, 10);
echo $rng->getNumber();
//> 5
echo $rng->getNumber();
//> 5
echo $rng->getNumber();
//> 5

更长的例子

假设有一个使用全局函数(例如time())的类,您想对其进行模拟。

<?php

namespace My\Crypto;

use Psr\Http\Message\RequestInterface as Request;

class Signer
{
    // ...

    public function getStringToSign(Request $request)
    {
        return $request->getMethod() . "\n"
            . time() . "\n"
            . $request->getHeader('X-API-Operation')[0] . "\n"
            . $request->getBody();            
    }
    
    // ...
}

以下是一个使用FuncMockertime()模拟为返回固定值的PHPUnit测试示例,这使得编写测试变得容易得多。

<?php

namespace My\App\Tests;

use FuncMocker\Mocker as FuncMocker;
use My\Crypto\Signer;
use Psr\Http\Message\RequestInterface as Request;

class SignerTest extends \PHPUnit_Framework_TestCase
{
    // ...

    public function testCanGetStringToSign()
    {
        // Mock the request with PHPUnit
        $request = $this->getMock(Request::class);
        $request->method('getMethod')->willReturn('POST');
        $request->method('getHeader')->willReturn(['CREATE_THING']);
        $request->method('getBody')->willReturn('PARAMS');
        
        // Mock the call to PHP's time() function to give us a deterministic value.
        FuncMocker::mock('time', 'My\Crypto', function () {
            return 12345;
        });
                
        $signer = new Signer();
        
        // Check to see that the string to sign is constructed how we would expect.
        $this->assertEquals(
            "POST\n12345\nCREATE_THING\nPARAMS",
            $signer->getStringToSign()
        );
    }
    
    // ...
}

禁用和重新启用

FuncMocker还允许您禁用您设置的模拟,以防您需要在某些测试中使用函数的正常行为。

$func = FuncMocker\Mocker::mock('time()', 'My\App', function () {
    return 1234567890;
});

echo My\App\time();
//> 1234567890

$func->disable();
echo My\App\time();
//> 1458018866

$func->enable();
echo My\App\time();
// > 1234567890

限制

  1. 要模拟的函数必须在使用全局命名空间之外的命名空间中使用。
  2. 要模拟的函数不得使用完全限定名进行引用(例如,\time())。

测试

$ composer test

致谢

替代方案

许可证

MIT许可证(MIT)。有关更多信息,请参阅许可证文件