web-dev-qa-db-fra.com

Méthode non définie sur un objet virtuel implémentant une interface donnée dans PHPUnit?

Je suis nouveau dans les tests unitaires et PHPUnit.

J'ai besoin d'une maquette sur laquelle je dispose d'un contrôle total, implémentant l'interface ConfigurationInterface. Le sujet du test est un objet ReportEventParamConverter et le test doit vérifier l'interaction entre mon objet et l'interface.

ReportEventParamConverter objet (ici simplifié):

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

Et voici comment j'essaie de me moquer de l'interface:

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

Je dois simuler les valeurs renvoyées pour deux méthodes: getClass() et getName(). Par exemple:

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

Quand je crée une nouvelle méthode ReportEventParamConverter et test supports(), j'obtiens l'erreur PHPUnit suivante:

Erreur fatale: appel de la méthode non définie Mock_ConfigurationInterface_21e9dccf :: getClass ().

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

C'est parce qu'il n'y a pas de déclaration de méthode "getClass" dans ConfigurationInterface. La seule déclaration dans cette interface est la méthode "getAliasName".

Tout ce dont vous avez besoin est de dire à la maquette quelles méthodes vous allez remplacer:

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

Notez qu'il n'y a pas de déclaration "getClass", mais vous pouvez également stub/simuler une méthode non existante. Vous pouvez donc vous moquer de ça:

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

Mais en plus, vous devez vous moquer de la méthode "getAliasName" aussi longtemps qu'il s'agit d'une méthode d'interface ou d'une méthode abstraite et qu'elle doit être "implémentée". Par exemple.:

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

La réponse de Cyprian m'a aidé, mais il faut être conscient de cela. Vous pouvez simuler des classes qui n'existent pas et PHPUnit ne se plaindra pas. Alors tu pourrais faire

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

Cela signifie que si ConfigurationInterface n'existe pas à ce moment-là pendant l'exécution, vous recevrez toujours un message du type

Erreur fatale: appel de la méthode non définie Mock_ConfigurationInterface_21e9dccf :: getClass ().

Si vous êtes certain que la méthode existe vraiment dans la classe, le problème est probablement que la classe elle-même n'existe pas (parce que vous ne l'avez pas demandée, ou que vous l'avez mal orthographiée, etc.).


L'OP utilise une interface interface . Sachez que vous devez appeler getMock sans spécifier la liste des méthodes à remplacer. Sinon, vous devez soit transmettre array(), soit transmettre TOUS les noms de méthodes, sinon vous obtiendrez une erreur comme celle-ci:

Erreur fatale PHP: La classe Mock_HttpRequest_a7aa9ffd contient 4 méthodes abstraites et doit donc être déclarée abstraite ou implémenter les méthodes restantes (HttpRequest :: setOption, HttpRequest :: execute, HttpRequest :: getInfo, ...)

13
Tyler Collier

L'avertissement de Tyler Collier est juste, mais ne contient pas d'extrait de code expliquant comment coder. Notez que c'est très méchant et que vous devriez plutôt réparer l'interface. Avec cet avertissement ajouté:

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