Laravel组件构造函数属性赋值测试:Eloquent属性Mock难题求解
解决方法
方案1:Mock Eloquent的魔术__get方法
Eloquent模型的属性访问(比如$category->children)本质是调用__get()魔术方法,你可以直接验证这个方法是否被调用,参数是'children':
it('assigns category children to categories property', function() { $mockCategory = Mockery::spy(\App\Models\Category::class); $this->component(\App\View\Components\Shop\Breadcrumb::class, [ 'category' => $mockCategory ]); // 验证__get方法被调用,参数是'children' $mockCategory->shouldHaveReceived('__get') ->once() ->with('children'); });
这个方法不用修改业务代码,直接针对Eloquent的属性访问机制做测试,完全符合你的需求——确保构造函数里确实取了children属性,而不是其他值。
方案2:直接断言组件的categories属性值
如果你不想用Mock,也可以用真实的模型实例(比如通过工厂创建),然后断言组件的categories和模型的children完全一致:
it('sets categories as category children', function() { // 创建带子分类的模型实例 $category = \App\Models\Category::factory() ->has(\App\Models\Category::factory()->count(2), 'children') ->create(); // 初始化组件 $component = $this->component(\App\View\Components\Shop\Breadcrumb::class, [ 'category' => $category ]); // 断言组件的categories属性等于模型的children集合 expect($component->categories)->toEqual($category->children); });
这个方案更偏向行为测试,验证的是最终结果是否正确,而不是具体调用了哪个属性。好处是不用依赖Mockery的细节,更贴近实际业务场景;缺点是如果children的实现变化,只要返回值还是子分类,测试依然通过——但这其实也符合你的需求,因为你只关心组件拿到的是子分类,不管children内部怎么实现。
关于你提到的包装方法
你想把children包装成getChildren()方法,这个方案是可行的,但确实会增加一层冗余代码,而且需要额外测试getChildren()方法。除非你有其他业务逻辑要加到这个方法里,否则没必要为了测试而额外封装。
总结来说,方案1最贴合你的需求(验证属性被调用),且不用修改业务代码;方案2更简洁,专注于结果验证,也是不错的选择。
内容的提问来源于stack exchange,提问作者Zakalwe
相关产品推荐
相关产品推荐

