【问题标题】:How to prevent PhpStorm from showing an Expected... warning when using PHPUnit mocks?使用 PHPUnit 模拟时如何防止 PhpStorm 显示 Expected... 警告?
【发布时间】:2014-10-17 08:22:44
【问题描述】:

在 PHPUnit 中模拟接口时,PhpStorm 会在将其用作类型提示函数的参数时报错。

示例

interface InterfaceA{                                

}                                                    

class ClassA{                                        
    public function foo(InterfaceA $foo){}           
}                                                    

class PhpStormTest extends PHPUnit_Framework_TestCase
{                                                    
    public function testFoo(){                       
        $mock = $this->getMock("InterfaceA");        
        $a = new ClassA();                           
        $a->foo($mock);                              
    }                                                
}   

$a->foo($mock); PhpStorm 下划线$mock 和警告Expected InterfaceA, got PHPUnit_Framework_MockObject_MockObject

图片

我猜这是因为 PHPUnit 创建了一个运行时的模拟,而 PhpStorm 无法知道它实际上是在实现接口。

【问题讨论】:

    标签: php unit-testing phpunit phpstorm type-hinting


    【解决方案1】:

    我在 Jetbrain 博客 PhpStorm Type Inference and Mocking Frameworks 中找到了解决此问题的方法。重要的部分:

    默认情况下,PhpStorm 能够找出可用的方法 在模拟对象上。但是,它只显示那些用于 PHPUnit 的 PHPUnit_Framework_MockObject_MockObject 类。幸运的是,我们可以 通过指示 PhpStorm 从 其他类也一样,使用简单的 docblock 注释。

    所以要让警告消失,我们需要添加 /** @var InterfaceA */ /** @var InterfaceA|PHPUnit_Framework_MockObject_MockObject */(对 Supericy 表示感谢)让 PhpStorm 知道我们的 mock 实际实现了 InterfaceA

    interface InterfaceA{                                
    
    }                                                    
    
    class ClassA{                                        
        public function foo(InterfaceA $foo){}           
    }                                                    
    
    class PhpStormTest extends PHPUnit_Framework_TestCase
    {                                                    
        public function testFoo(){   
            /** @var InterfaceA|PHPUnit_Framework_MockObject_MockObject */            
            $mock = $this->getMock("InterfaceA");        
            $a = new ClassA();                           
            $a->foo($mock);                              
        }                                                
    } 
    

    这困扰了我一段时间,希望对某人有所帮助:)

    编辑

    由于PHPUnit_Framework_MockObject_MockObject 很难输入,您可以通过MOOMOO 缩写它,然后让PHPStorms 自动完成剩下的工作:

    【讨论】:

    • 如果你也在模拟方法,你可以使用/** @var InterfaceA|PHPUnit_Framework_MockObject_MockObject */,所以它会为两个类输入提示。
    • +1 @Supericy,被模拟的对象还继承了模拟对象接口方法expects(),如果你忽略同时指定InterfaceA和@987654335,这会带回phpStorm抱怨找不到方法@
    • 糟糕的是,像 Scrutinizer 这样的 CI 工具会读取这些注释并将您的模拟变量视为一个问题,因为(例如)“预期的方法只存在于 PHPUnit_Framework_MockObject_MockObject 中,而不存在于 InterfaceA 中”。它将被标记为问题,您的代码评级将受到影响......!
    • 来自 phpstorm blog.jetbrains.com/webide/2013/01/…的文档
    【解决方案2】:

    我为此使用的另一个插件是Dynamic Return Type Plugin,它可以让您以非常动态的方式配置方法的返回类型(示例是从 Mocks 获得更好的类型信息)。

    【讨论】:

      【解决方案3】:

      另一种不那么冗长但可能风险更大的方法是使用您自己的函数包装对getMock() 的调用,并用@return mixed 标记它:

      /**
      *
      * @return mixed
      */
      public function myGetMock($str) 
      {
          return $this->getMock($str);
      }
      

      调用此方法而不是$this->getMock() 将使警告消失。

      【讨论】:

      • 恕我直言,为软件引入新接口以使 IDE 保持愉快是完全错误的。 IDE 应该适用于开发用例,而不是软件本身。按照接受的答案中的建议添加内联文档块TypeA|TypeB 是可行的方法。
      猜你喜欢
      • 2016-06-20
      • 2021-03-25
      • 1970-01-01
      • 2020-04-11
      • 2021-12-25
      • 2015-12-24
      • 2021-04-09
      • 1970-01-01
      • 2018-12-27
      相关资源
      最近更新 更多