PHPSpec 不能做很多你可以做的事情,例如,用 PHPUnit 和 Mockery 做的事情。
底线:我想说 PHPSpec 不是测试 Eloquent 的正确工具。
Eloquent 内部发生了很多“魔法”,而 PHPSpec 似乎并不喜欢魔法,如果您觉得必须使用 PHPSpec 来测试 Eloquent,否则世界将崩溃,那么您可以做一些事情。
免责声明: 我不鼓励你继续使用 PHPSpec 进行 Eloquent 测试,事实上我不希望你用它来测试 eloquent 模型,我只是解释一些技巧来解决你在测试魔法方法时会遇到的情况和黑色艺术——希望你能在有意义的时候将它们应用到其他地方。对我来说,在 Eloquent 模型的情况下它没有意义。
所以这里是列表:
- 不要使用魔法 getter 和 setter,使用
getAttribute()
andsetAttribute()
代替
- 不要对延迟加载的关系使用魔术调用,即
$user->profile
. 使用方法$user->profile()->getResults()
- 创建一个 SUT 模拟类来扩展您的模型并
where
在其上定义这些方法,还定义范围方法以及 Eloquent 应该“神奇地”为您做的所有其他事情。
- 使用
beAnInstanceOf()
方法切换到模拟并对其进行断言。
这是我的测试的示例:
产品型号
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function scopeLatest($query)
{
return $query->where('created_at', '>', new Carbon('-1 week'))
->latest();
}
// Model relations here...
}
产品型号规格
<?php namespace Spec\Model;
use Prophecy\Argument;
use App\Entities\Product;
use PhpSpec\ObjectBehavior;
class ProductSpec extends ObjectBehavior
{
public function let()
{
$this->beAnInstanceOf(DecoyProduct::class);
}
public function it_is_initializable()
{
$this->shouldHaveType('Product');
}
}
// Decoy Product to run tests on
class DecoyProduct extends Product
{
public function where();
// Assuming the Product model has a scope method
// 'scopeLatest' on it that'd translate to 'latest()'
public function latest();
// add other methods similarly
}
通过在诱饵类上定义where
andlatest
方法并将其设置为 SUT,您可以让 PHPSpec 知道这些方法实际上存在于类中。它们的参数和返回类型无关紧要,只有存在。
优势 ?
现在,在您的规范中,当您在模型上调用->where()
或->latest()
方法时,PHPSpec 不会抱怨它,您可以更改诱饵类上的方法以返回一个对象Prophecy
并对其进行断言。