dqrnskni67375 2019-07-04 15:05
浏览 109
已采纳

PHPUnit - 调用Assert trait方法

Supposing I have a trait which currently has a method:

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

Now let's say this trait is used by several classes but I don't want to write a unit-test for every class. Instead I want to write a single unit-test only for the trait:

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

But the problem is that a class may actually override trait's method:

class MyClass
{
    use MyTrait;

    public function traitMethod()
    {
        return false;
    }
}

In this case MyClass is doing something wrong but I'm not aware of it since I'm testing only the trait.

My idea would be write a single unit-test for every class just to check if it's using that trait and it's not overriding that method. If a class needs to override trait's method then it needs a specific unit-test as well.

Currently I'm writing unit-tests for each class that implements my trait but it's of course kind of copy-paste tests everywhere.

So is there a way to test if a class calls it's underlying trait method?

  • 写回答

1条回答 默认 最新

  • drpogkqqi536984960 2019-07-05 14:15
    关注

    I found a solution using Reflection, I'll post it in case someone needs it because I couldn't find anything related to my problem. Feel free to comment or add different solutions if you want.

    So the following test asserts that $serviceClass uses $traitClass and doesn't override methods declared in $traitClass except abstract ones and those which are manually added to $overriddenMethods array.

    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
            ));
        }
    }
    

    I also tried to compare declaring classes using $classMethod->getDeclaringClass() instead of comparing filenames but it didn't work: even if trait method is not overridden in class, getDeclaringClass() always returns the class itself.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 【急】在线问答CNC雕刻机的电子电路与编程
  • ¥60 在mc68335芯片上移植ucos ii 的成功工程文件
  • ¥15 笔记本外接显示器正常,但是笔记本屏幕黑屏
  • ¥15 Python pandas
  • ¥15 蓝牙硬件,可以用哪几种方法控制手机点击和滑动
  • ¥15 生物医学数据分析。基础课程就v经常唱课程舅成牛逼
  • ¥15 云环境云开发云函数对接微信商户中的分账功能
  • ¥15 空间转录组CRAD遇到问题
  • ¥20 materialstudio计算氢键脚本问题
  • ¥15 有没有代做有偿主要做数据可视化部分即可(2023全国高考更省一本线理科类)