13

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

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

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

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

4

4 回答 4

10

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

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

于 2009-08-07T20:25:12.200 回答
1

这是一篇关于模拟全局 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());
    }
}

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

于 2016-04-13T10:25:44.943 回答
0

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

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

于 2011-05-24T20:54:13.507 回答
0

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

于 2015-08-31T06:04:17.950 回答