web-dev-qa-db-ja.com

PHPUnitで特定のインターフェースを実装するモックオブジェクトの未定義のメソッド?

私はユニットテストとPHPUnitに不慣れです。

ConfigurationInterfaceインターフェースを実装する完全な制御が可能なモックが必要です。テスト対象はReportEventParamConverterオブジェクトであり、テストではオブジェクトとインターフェイス間の相互作用を確認する必要があります。

ReportEventParamConverterオブジェクト(ここでは簡略化):

_class ReportEventParamConverter implements ParamConverterInterface
{
    /**
     * @param Request $request
     * @param ConfigurationInterface $configuration
     */
    function apply(Request $request, ConfigurationInterface $configuration)
    {
        $request->attributes->set($configuration->getName(), $reportEvent);
    }

    /**
     * @param ConfigurationInterface $configuration
     * @return bool
     */
    function supports(ConfigurationInterface $configuration)
    {
        return 'My\Namespaced\Class' === $configuration->getClass();
    }
}
_

そして、これは私がインターフェースをモックしようとしている方法です:

_$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface';
$mock = $this->getMock($mockCls);
_

getClass()getName()の2つのメソッドの戻り値をシミュレートする必要があります。例えば:

_$mock->expects($this->any())
    ->method('getClass')
    ->will($this->returnValue('Some\Other\Class'))
;
_

新しいReportEventParamConverterメソッドを作成してsupports()メソッドをテストすると、次のPHPUnitエラーが発生します。

致命的なエラー:未定義のメソッドMock_ConfigurationInterface_21e9dccf :: getClass()を呼び出します。

_$converter = new ReportEventParamConverter();
$this->assertFalse($converter->supports($mock));
_
19
gremo

これは、ConfigurationInterfaceに「getClass」メソッドの宣言がないためです。このインターフェースでの唯一の宣言は、メソッド「getAliasName」です。

必要なのは、スタブするメソッドをモックに伝えることだけです。

$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface';
$mock = $this->getMock($mockCls, array('getClass', 'getAliasName'));

「getClass」宣言はありませんが、存在しないメソッドをスタブ/モックすることもできます。そのため、あなたはそれをあざけることができます:

$mock->expects($this->any())
    ->method('getClass')
    ->will($this->returnValue('Some\Other\Class'));

ただし、それに加えて、インターフェイスのメソッドまたは抽象メソッドであり、「実装」する必要がある限り、「getAliasName」メソッドをモックする必要があります。例えば。:

$mock->expects($this->any())
   ->method('getAliasName')
   ->will($this->returnValue('SomeValue'));
18
Cyprian

キプリアンの答えは私を助けましたが、注意すべき落とし穴があります。存在しないクラスをモックすることができ、PHPUnitは文句を言いません。だからあなたはすることができます

_$mock = $this->getMock('SomeClassThatDoesntExistOrIsMisspelledOrPerhapsYouForgotToRequire');
_

つまり、実行時のその時点でConfigurationInterfaceが存在しない場合でも、次のようなメッセージが表示されます。

致命的なエラー:未定義のメソッドMock_ConfigurationInterface_21e9dccf :: getClass()を呼び出します。

メソッドが実際にクラスに存在することが確実な場合、問題として考えられるのは、クラス自体が存在しないことです(必要がない、またはスペルを間違えたなどの理由で)


OPはインターフェースを使用しています。オーバーライドするメソッドのリストを指定せずにgetMockを呼び出す必要があることに注意してください。呼び出す場合は、array()を渡すか、すべてのメソッド名を渡す必要があります。そうしないと、次のようになります。次のようなエラー:

PHPの致命的なエラー:クラスMock_HttpRequest_a7aa9ffdには4つの抽象メソッドが含まれているため、抽象として宣言するか、残りのメソッドを実装する必要があります(HttpRequest :: setOption、HttpRequest :: execute、HttpRequest :: getInfo、...)

13
Tyler Collier

Tyler Collierの警告は公正ですが、その周りのコーディング方法に関するコードスニペットは含まれていません。これは非常に厄介であり、代わりにインターフェイスを修正する必要があることに注意してください。その警告が追加されました:

$methods = array_map(function (\ReflectionMethod $m) { return $m->getName();}, (new \ReflectionClass($interface))->getMethods());
$methods[] = $missing_method;
$mock = $this->getMock($interface,  $methods);
1
chx