为什么我的过滤关系集合是空的,尽管模拟了有效的 HasMany 关系?

问题描述 投票:0回答:1

我正在编写一个单元测试来过滤掉模型中的无效关系。目标是仅保留模型中实际存在的关系。但是,我的测试失败了,因为过滤后的关系集合返回为空,即使我已经模拟了其中一个关系

validRelation
返回有效的 HasMany 关系。

其他背景:

  • 我正在使用 Laravel 和 Mockery 进行单元测试。

  • filterRestrictedRelations
    方法受到保护,因此我通过反射调用它。

  • 我尝试将方法设置为

    public
    并省略反射部分,但集合仍然是空的 - 看起来问题在于 Mockery 如何处理
    shouldReceive('validRelation')

什么可能导致此行为,以及如何正确测试有效关系是否未被过滤掉?

protected function filterRestrictedRelations(): void
{
    $this->restrictedRelations = $this->restrictedRelations->filter(function ($relation) {
        $exists = method_exists($this->model, $relation);
        dump("Checking relation: $relation, exists: " . ($exists ? 'true' : 'false'));
        return $exists;
    });
}

enter image description here

这是我测试的相关部分:

public function setUp(): void
{
    parent::setUp();
    $this->model = \Mockery::mock(AnAbstractClass::class)->makePartial();
    $this->modelRelation   = \Mockery::mock(new ModelRelation($this->model));
    $this->reflectionClass = new ReflectionClass($this->modelRelation);
}


public function it_filters_out_relations_that_do_not_exist_in_model(): void
{
    $relations = ['validRelation', 'invalidRelation1', 'invalidRelation2'];

    // Mocking model to have the 'validRelation' method returning a HasMany relation
    $this->model->shouldReceive('validRelation')
                ->andReturn(\Mockery::mock(HasMany::class));

    $this->modelRelation = new ModelRelation($this->model);
    $this->modelRelation->setRestrictedRelations($relations);

    $this->reflectionClass = new ReflectionClass($this->modelRelation);

    // Invoke the filterRestrictedRelations method
    $this->reflectionClass->getMethod('filterRestrictedRelations')
                          ->invoke($this->modelRelation);

    $filteredRelations = $this->reflectionClass->getMethod('getRestrictedRelations')->invoke($this->modelRelation);

    // Check that invalidRelation1 remains, while others are filtered out
    $this->assertEquals(['validRelation'], $filteredRelations->all());
}
laravel unit-testing phpunit mockery
1个回答
0
投票

当使用 Mockery 模拟现有类时,

method_exists()
函数将为原始类中实际存在的任何方法返回 true,但对于不存在的方法,它将返回 false,即使您使用
shouldReceive()

发生这种情况是因为

shouldReceive()
没有以常规方式创建方法;相反,它利用
__call()
魔术方法进行方法重载。

Mockery 提供了一种方法来验证模拟是否需要特定的方法调用。您可以确定模拟是否对该特定方法设置了任何期望,而不是使用 method_exists()。

protected function filterRestrictedRelations(bool $mocking = false): void
{
    $this->restrictedRelations = $this->restrictedRelations->filter(function ($relation) {
        return method_exists($this->model, $relation) || ($mocking && $this->model->mockery_getExpectationsFor($relation));
    });
}
© www.soinside.com 2019 - 2024. All rights reserved.