PHPUnit-断言特征方法被调用

时间:2019-07-04 15:05:49

标签: php unit-testing mocking phpunit

假设我具有当前具有方法的特征:

trait MyTrait
{
    public function traitMethod()
    {
        return true;
    }
}

现在让我们说这个特征已被多个类使用,但我不想为每个类编写一个单元测试。 相反,我只想为特征编写一个单元测试:

public function testTraitMethod()
{
    $trait = $this->getMockForTrait(MyTrait::class);
    $this->assertTrue($trait->traitMethod());
}

但是问题是,一个类实际上可能覆盖特质的方法:

class MyClass
{
    use MyTrait;

    public function traitMethod()
    {
        return false;
    }
}

在这种情况下,MyClass做错了事,但由于仅测试特征,所以我不知道。

我的想法是为每个类编写一个单元测试,只是为了检查它是否正在使用该特性并且没有覆盖该方法。如果一个类需要重写trait的方法,那么它也需要一个特定的单元测试。

目前,我正在为实现我的特质的每个类编写单元测试,但是当然到处都是复制粘贴测试。

那么有没有一种方法可以测试一个类是否调用了它的基础特征方法?

1 个答案:

答案 0 :(得分:0)

我找到了使用Reflection的解决方案,我将其发布,以防万一有人需要它,因为我找不到与问题相关的任何东西。随意发表评论或添加其他解决方案。

因此,以下测试断言$serviceClass使用$traitClass,并且不覆盖$traitClass中声明的方法,除了抽象方法和那些手动添加到$overriddenMethods数组中的方法。

public function testServiceUsesTrait()
{
    $serviceClass = MyClass::class;
    $traitClass = MyTrait::class;

    $this->assertContains($traitClass, (new \ReflectionClass($serviceClass))->getTraitNames());

    $reflectedTrait = new \ReflectionClass($traitClass);
    $reflectedTraitFile = $reflectedTrait->getFileName();

    /**
     * If $serviceClass overrides some trait methods they
     * should be inserted into this array to avoid test failure.
     * Additional unit-tests should be written for overridden methods.
     */
    $overriddenMethods = [];

    foreach ($reflectedTrait->getMethods() as $traitMethod) {
        if ($traitMethod->isAbstract() || in_array($traitMethod->getName(), $overriddenMethods, true)) {
            continue;
        }
        $classMethod = new \ReflectionMethod($serviceClass, $traitMethod->getName());
        $this->assertSame($reflectedTraitFile, $classMethod->getFileName(), sprintf(
            'Trait method "%s" is overridden in class "%s" thus it must be excluded from this test.',
            $traitMethod->getName(), $serviceClass
        ));
    }
}

我还尝试了使用$classMethod->getDeclaringClass()而不是文件名来比较声明类,但是它没有用:即使trait方法没有在类中被覆盖,getDeclaringClass()总是返回类本身。