如何对这个PHP函数进行单元测试和重构?

时间:2013-05-28 09:51:44

标签: php unit-testing yii

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

我的问题很简单:如何 单元 测试以下方法以及我应该做哪些重构才能使其可测试?我再说一遍:我不想要求使用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->dbCDbConnection个对象。 $this->db->createCommand()会返回CDbCommand个对象。

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

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

  1. 数据库的接口使用工厂方法,该方法返回具有可链接方法的对象。这是嘲笑的噩梦。我开始为CDbCommand和创建它的CDbConnection编写一个手动假,但是我已经写了很多代码,它可能需要它自己的单元测试。我根本不明白我应该如何模拟对数据库的请求。
  2. 这段代码只是一个例子。我有很多类似的方法,但是他们中的很多人不是一次调用数据库,而是多次,所以“获取原始数据,重新格式化”可能不是这里的模式,但我不确定。
  3. 最后:我在这里测试的是由相关PHPUnit测试方法的名称描述的:

    public function CanFindNumberOfOrdersGroupedByStatus()
    

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

    我想知道是否需要为CDbConnection实现完整的后端,它将与内存中的灯具配合使用,而不是真正的数据库,以便对这些方法进行适当的单元测试。

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

1 个答案:

答案 0 :(得分:-1)

您根本不需要编写太多代码来测试它。 Yii拥有出色的测试框架,包括数据库测试和数据库夹具功能,可以完美地覆盖这一传统功能。

供你阅读:

Testing in Yii(另见其中的灯具部分)

一般来说,你最终会做的是:

  1. 按照指南中的规定设置测试配置和测试引导程序文件(默认示例应用程序将包含示例测试配置/引导程序设置)。
  2. 使用架构创建测试数据库并将测试配置指向该处。
  3. 编写一个扩展CDbTestCase的类。这只是普通的PHPUnit测试,使用Yii的特殊附加功能,可以更轻松地使用数据库夹具进行测试。如果您不熟悉PHPUnit,请参阅the docs
  4. 根据Yii指南为您的测试数据库写一些灯具。这可确保测试数据库的测试数据。
  5. 编写调用Order类功能的测试"按原样#34;和普通单元测试一样断言结果,例如(这个代码在你的单元测试CDbTestCase子类中):

    $这 - >的assertEquals(   数组(1 => 2,2 => 5),   为了::模型() - > getOrderCountGroupedByStatus() );