繁体   English   中英

在单元测试中模拟PHP函数

[英]Mocking PHP functions in unit tests

我用SimpleTest对一些PHP代码进行单元测试,但我遇到了麻烦。 在我对数据库类的测试中,我希望能够为PHP的mysql函数设置期望。 在我对mail函数的包装类的测试中,我想模拟PHP的mail功能。 这只是一些例子。

关键是:我不(总是)想测试我的Mail类是否发送电子邮件,我想测试它如何调用mail功能。 我希望能够控制这些函数返回的内容。 我希望能够测试我的数据库类,而不需要数据库,灯具和那么多。

我有一些测试Ruby代码的经验,而Test :: Unit和RSpec使得单独测试代码非常容易。 我是测试PHP的新手,感觉我测试的内容比我需要的要多得多,以便让我的测试通过。

在SimpleTest或PhpUnit或其他一些测试框架中是否有办法使这成为可能或更容易?

不是以自动方式。 你可以做的是编写代码,使外部依赖包装在从外部传入的对象中。 在您的生产环境中,您只需连接真正的适配器,但在测试期间,您可以将其连接到存根或模拟。

如果你真的坚持,你可以使用runkit扩展来改变php的编程模型,这样你就可以在运行时重新定义类和函数。 这是一个外部和非标准的扩展,但是,请记住这一点。 如上所述,事实上的标准是手动方法。

这是一篇关于模拟全局php函数的有趣文章 作者通过覆盖SUT命名空间(被测试服务)内的方法,提出了一个非常有创意的解决方案,以解决全局php函数的“模拟”问题。

这里的代码来自博客文章中模拟time函数的示例:

<?php

namespace My\Namespace;

use PHPUnit_Framework_TestCase;

/**
 * Override time() in current namespace for testing
 *
 * @return int
 */
function time()
{
    return SomeClassTest::$now ?: \time();
}

class SomeClassTest extends PHPUnit_Framework_TestCase
{
    /**
     * @var int $now Timestamp that will be returned by time()
     */
    public static $now;

    /**
     * @var SomeClass $someClass Test subject
     */
    private $someClass;

    /**
     * Create test subject before test
     */
    protected function setUp()
    {
        parent::setUp();
        $this->someClass = new SomeClass;
    }

    /**
     * Reset custom time after test
     */
    protected function tearDown()
    {
        self::$now = null;
    }

    /*
     * Test cases
     */
    public function testOneHourAgoFromNoon()
    {
        self::$now = strtotime('12:00');
        $this->assertEquals('11:00', $this->someClass->oneHourAgo());
    }
    public function testOneHourAgoFromMidnight()
    {
        self::$now = strtotime('0:00');
        $this->assertEquals('23:00', $this->someClass->oneHourAgo());
    }
}

不确定这是否是一个很好的方法,但它肯定运作良好,我认为这里值得一提。 可以作为讨论的一些食物......

在PHP 5.3+环境中,您可以通过破解命名空间来解决使用runkit扩展的需要。 函数调用的唯一要求是不使用完全限定的命名空间,如\\mysql_query() - 而且它们通常不会。 然后,您可以在测试中定义相同的函数,方法是在命名空间中定义测试,PHP将调用您的函数而不是全局函数。 我个人使用这种方法来存根time()函数调用。 这是一个嘲弄框架好例子

有一个PHPUnit扩展在内部使用runkit,并且能够使用调用匹配器,参数约束和模拟对象可以执行的所有操作。

https://github.com/tcz/phpunit-mockfunction

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM