<?php
use yii\db\ActiveRecord;
class Model extends ActiveRecord
{
protected static $ids = [];
public static function getIds()
{
if (empty(static::$ids)) {
static::$ids = static::find()->select('id')->column();
}
return static::$ids;
}
}
如何通过反复调用此方法来确保查询执行一次?
最好使用codeception或phpunit。
答案 0 :(得分:3)
测试不仅是确保代码工作的一种方式,还有助于识别代码异味。在你的情况下编写测试很难,因为你使用静态方法。
曾经有一个staticExpects
方法,但很久以前在phpunit中已经弃用了,所以这不太可行。使此代码可测试的最佳方法是删除static
关键字。对于getIds()
来说这很容易,但由于静态find()
是由第三方(yii的ActiveRecord)定义的,因此您无法真正删除它。相反,你可以用非静态方法包装它。通过触摸包含第三方代码的这些小方法,这使您能够从将Active Record转移到Doctrine之类的其他实现中。
执行此操作后,您可以创建模型的部分模拟,以确保调用该方法:
class Model extends ActiveRecord
{
private $ids;
protected function findIds()
{
return static::find()->select('id')->column();
}
public function getIds()
{
if (empty($this->ids)) {
$this->ids = $this->findIds()
}
return $this->ids;
}
}
并在你的测试中:
public function testFindIdsIsCalledWhenGetterIsNotInitialized()
{
$model = $this->getMockBuilder(Model::class)
->setMethods(['findIds'])
->getMock();
$model->expects($this->once())
->method('findIds')
->will($this->returnValue([1, 2, 3]));
$ids = $model->getIds();
$this->assertEquals([1, 2, 3], $ids);
}
这应该有2个断言,一个用于预期的方法调用,一个用于返回的值。此测试绕过活动记录,仅确保您的getIds()
方法按预期工作。另一种解决方法是,如您的问题评论中所述,使用功能测试,通过从(测试)数据库中获取数据来实际测试数据库交互。显然,因为这需要具有数据库连接并检索测试数据,例如,从一些以前设置的灯具,它是更多的工作,测试将更慢。根据您的项目有多大可能不是问题而且您可能更愿意在Active Record实现中测试逻辑。