Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在单元测试中模拟PHP函数_Php_Unit Testing_Mocking_Simpletest - Fatal编程技术网

在单元测试中模拟PHP函数

在单元测试中模拟PHP函数,php,unit-testing,mocking,simpletest,Php,Unit Testing,Mocking,Simpletest,我正在用SimpleTest对一些PHP代码进行单元测试,结果遇到了麻烦。在对数据库类的测试中,我希望能够为PHPsmysql函数设置期望值。在测试mail函数的包装类时,我想模拟PHPsmail函数。这些只是一些例子 要点是:我不(总是)想测试我的邮件类是否发送电子邮件,我想测试它如何调用Mail函数。我希望能够控制这些函数返回的内容。我希望能够测试我的数据库类,而不需要数据库、固定装置等 我有一些测试Ruby代码的经验,Test::Unit和RSpec使隔离测试代码变得非常容易。我是测试PH

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

要点是:我不(总是)想测试我的邮件类是否发送电子邮件,我想测试它如何调用
Mail
函数。我希望能够控制这些函数返回的内容。我希望能够测试我的数据库类,而不需要数据库、固定装置等

我有一些测试Ruby代码的经验,Test::Unit和RSpec使隔离测试代码变得非常容易。我是测试PHP的新手,为了让我的测试通过,我觉得我测试的内容比我应该做的要多得多


SimpleTest、PhpUnit或其他一些测试框架中是否有一种方法使这成为可能或更简单?

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


如果您真的坚持,可以使用更改php编程模型的命令,以便在运行时重新定义类和函数。不过,这是一个外部的非标准扩展,请记住这一点。正如我前面所描述的,事实标准是一种手动方法。

有一个PHPUnit扩展,它在内部使用runkit,并且能够使用调用匹配器、参数约束和模拟对象可以做的一切


在PHP5.3+环境中,您可以通过破解名称空间来解决使用
runkit
扩展的问题。唯一的要求是函数调用不使用完全限定的名称空间,如
\mysql\u query()
——它们通常不使用。然后,通过在命名空间中定义测试,您可以在测试中定义相同的函数,PHP将调用您的函数,而不是全局函数。我个人使用这种方法来存根
time()
函数调用。下面是一篇关于模拟全局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());
    }
}

我明白了。我有点期待(但不希望)这样的答案。我并不是真的坚持,因为我想简化和加速测试,而不是让它变得更复杂。谢谢你的回复!现在看来,@Franco不适用于内置。您可以使用来创建此类模拟。