【问题标题】:How to unit test and refactor this PHP function?如何对这个 PHP 函数进行单元测试和重构?
【发布时间】:2013-05-28 09:51:43
【问题描述】:

免责声明:是的,我已阅读常见问题解答并在 Stackoverflow 的范围内思考这样的问题。不,我不知道如何正确命名它。 :(

我的问题很简单:如何unit测试以下方法,我应该进行哪些重构以使其可测试?我再说一遍:我不想让 DB 和 Yii 应用程序实例浮动来测试这个功能。

public function getOrderCountGroupedByStatus()
{
    $arr = $this->db->createCommand()
        ->select('COUNT( status ) AS count_status, status')
        ->from('order_item')
        ->group('status')
        ->order('status')
        ->queryAll();

    $orderItemsCountByStatus = array();
    foreach($arr as $os)
        $orderItemsCountByStatus[(int)$os['status']] = $os['count_status'];

    return $orderItemsCountByStatus;
}

这是通过手动测试整个应用程序来检查有效性的遗留代码。

它来自基于Yii framework的PHP应用程序。

$this->db 是一个 CDbConnection 对象。 $this->db->createCommand() 返回一个 CDbCommand 对象。

CDbCommand.queryAll() 返回可迭代对象,该对象在每次迭代时发出一个数组 array('status' => (string), 'count_status' => (int))

这个方法显然有两个职责:第一个从外部数据源获取原始数据,第二个将原始数据重新排列为最终结果。我知道它应该以某种方式分开。

  1. 数据库接口使用工厂方法,它返回一个带有可链接方法的对象。这是一个可以嘲笑的噩梦。我开始为 CDbCommand 和创建它的 CDbConnection 编写手动伪造,但我已经编写了很多代码,它可能需要它自己的单元测试。我完全不明白我应该如何模拟对数据库的请求。
  2. 此代码只是一个示例。我有很多类似的方法,但是很多都不是一次调用数据库,而是多次调用,所以“获取原始数据,重新格式化”可能不是这里的模式,但我不确定。

最后:我这里测试的是相关PHPUnit测试方法的名称来描述的:

public function CanFindNumberOfOrdersGroupedByStatus()

我卡在这里的主要原因是我测试的基本上是SUT 是否可以成功地从持久性存储中获取一些统计信息,仅此而已。与数据库的所有交互都是此处的实现细节,但在我正在使用的遗留代码库中,它是连接到持久性存储的唯一方法(使用上面的 CDbCommand/CDbConnection 组合),并且这种持久性存储是 MySQL 数据库。

我想知道我是否需要为 CDbConnection 实现完整的后端,该后端将与内存中的固定装置而不是真实的数据库一起使用,以正确地对此类方法进行单元测试。

是的,为了避免可能的问题,项目政治禁止使用 Yii 框架中内置的 ActiveRecords。

【问题讨论】:

  • 设置一个单独的测试数据库并简单地测试已知结果?
  • @IvoRenkema 伙计,我在这里谈论unit 测试。整个问题是根本使用真正的数据库,否则每个人都知道如何测试这样的功能。

标签: php unit-testing yii


【解决方案1】:

您根本不需要编写太多代码来测试它。 Yii 有一个优秀的测试框架,包括 DB 测试和 DB Fixture 功能,可以完美地覆盖这个遗留功能。

供您阅读:

Testing in Yii(另请参阅其中的固定装置部分)

通常你最终会做的是:

  1. 按照指南中的说明设置测试配置和测试引导文件(默认示例应用将包含示例测试配置/引导设置)。
  2. 使用架构创建测试数据库并将您的测试配置指向该数据库。
  3. 编写一个扩展CDbTestCase 的类。这只是您的普通 PHPUnit 测试,带有 Yii 的特殊添加,使使用 DB 固定装置进行测试更容易。如果您不熟悉 PHPUnit,请参阅the docs
  4. 根据 Yii 指南为您的测试数据库编写一些固定装置。这可以确保您的测试数据库的测试数据。
  5. 编写测试“按原样”调用 Order 类的函数并断言结果,就像在普通单元测试中一样,例如(此代码在您的单元测试 CDbTestCase 子类中):

    $this->assertEquals( 数组(1 => 2, 2 => 5), Order::model()->getOrderCountGroupedByStatus() );

【讨论】:

  • 我已经回复了一位评论者,给你同样的答案:我既不需要也不想为了测试这个功能而启动整个 MySQL 实例并实例化 Yii 应用程序。我想要 unit 测试,而不是集成测试。谢谢,我完全知道如何使用 Yii 设置数据库测试,去过那里,做到了。
猜你喜欢
  • 2013-05-22
  • 1970-01-01
  • 2021-12-03
  • 2010-09-26
  • 1970-01-01
  • 2022-11-12
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多