Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/277.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_Yii - Fatal编程技术网

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

如何对这个PHP函数进行单元测试和重构?,php,unit-testing,yii,Php,Unit Testing,Yii,免责声明:是的,我已经阅读了常见问题,并认为这样的问题存在于Stackoverflow的边界之内。不,我不知道如何正确命名( 我的问题很简单:如何单元测试以下方法,以及我应该做什么重构以使其可测试?我重复:我不想要求DB和Yii应用程序实例四处浮动来测试此函数 public function getOrderCountGroupedByStatus() { $arr = $this->db->createCommand() ->select('COUNT

免责声明:是的,我已经阅读了常见问题,并认为这样的问题存在于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;
}
这是通过手动测试整个应用程序来检查遗留代码的有效性

它来自基于PHP的应用程序

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

CDbCommand.queryAll()
返回iterable对象,该对象在每次迭代时发出数组
array('status'=>(string),'count\u status'=>(int))

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

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

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

    我想知道是否需要为CDbConnection实现完整的后端,它将与内存中的fixture而不是真正的DB一起工作,以正确地对这些方法进行单元测试


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

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

    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;
    }
    
    请阅读:

    (另请参见其中有关固定装置的章节)

    通常情况下,您最终要做的是:

  • 按照指南中的规定设置测试配置和测试引导文件(默认示例应用程序将包含示例测试配置/引导设置)
  • 使用schema创建测试数据库,并将测试配置指向该位置
  • 编写一个扩展类。这只是您的普通PHPUnit测试,Yii的特殊添加使使用DB fixture进行测试更容易。如果您不熟悉PHPUnit,请参阅
  • 根据Yii指南为测试数据库编写一些夹具。这确保了测试数据库的测试数据
  • 编写测试,调用Order类的函数“按原样”并断言结果,就像在普通单元测试中一样,例如(单元测试CDbTestCase子类中的此代码):

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


  • 设置一个单独的测试数据库并简单地测试已知的结果?@IvoRenkema Man,我在这里谈论的是
    单元
    测试。整个问题是根本不要使用真正的数据库,否则每个人都知道如何测试这样的函数。我已经回答了一位评论者,回答了你同样的问题:我不需要也不想提出整个MySQL实例实例化Yii应用程序只是为了测试这个功能。我想要单元测试,而不是集成测试。谢谢你,我完全知道如何使用Yii设置DB测试,已经完成了。