web-dev-qa-db-de.com

Undefinierte Methode für ein Scheinobjekt, das eine bestimmte Schnittstelle in PHPUnit implementiert?

Ich bin neu in Unit Testing und PHPUnit.

Ich brauche ein Mock, auf dem ich die volle Kontrolle habe und das ConfigurationInterface Interface implementiere. Testobjekt ist ReportEventParamConverter Objekt und Test muss die Interaktion zwischen meinem Objekt und der Schnittstelle überprüfen.

ReportEventParamConverter Objekt (hier vereinfacht):

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

Und so versuche ich das Interface zu verspotten:

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

Ich muss die zurückgegebenen Werte für zwei Methoden simulieren: getClass() und getName(). Zum Beispiel:

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

Wenn ich eine neue ReportEventParamConverter- und test supports()-Methode erstelle, erhalte ich den folgenden PHPUnit-Fehler:

Schwerwiegender Fehler: Aufruf der undefinierten Methode Mock_ConfigurationInterface_21e9dccf :: getClass ().

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

Dies liegt daran, dass es in ConfigurationInterface keine Deklaration der Methode "getClass" gibt. Die einzige Deklaration in dieser Schnittstelle ist die Methode "getAliasName".

Alles, was Sie brauchen, ist dem Mock zu sagen, mit welchen Methoden Sie stubben werden:

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

Beachten Sie, dass es keine "getClass" -Deklaration gibt, aber Sie können auch eine nicht vorhandene Methode stub/mocken. Dafür können Sie es verspotten:

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

Zusätzlich müssen Sie jedoch die Methode "getAliasName" sowie die Methode der Schnittstelle oder die abstrakte Methode "implementieren". Z.B.:

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

Die Antwort von Cyprian hat mir geholfen, aber es gibt ein Problem, dessen man sich bewusst sein muss. Sie können Klassen verspotten, die es nicht gibt, und PHPUnit wird sich nicht beschweren. Also könntest du tun

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

Das heißt, wenn ConfigurationInterface zu diesem Zeitpunkt zur Laufzeit nicht vorhanden ist, erhalten Sie trotzdem eine Meldung wie

Schwerwiegender Fehler: Aufruf der undefinierten Methode Mock_ConfigurationInterface_21e9dccf :: getClass ().

Wenn Sie sicher sind, dass die Methode tatsächlich in der Klasse vorhanden ist, besteht das Problem wahrscheinlich darin, dass die Klasse selbst nicht vorhanden ist (weil Sie sie nicht benötigt haben oder sie falsch geschrieben haben usw.).


Das OP verwendet eine Schnittstelle . Beachten Sie, dass Sie getMock aufrufen müssen, ohne die Liste der zu überschreibenden Methoden anzugeben. Andernfalls müssen Sie entweder array() übergeben oder ALLE Methodennamen übergeben. Anderenfalls wird eine Fehlermeldung wie die folgende angezeigt:

Schwerwiegender PHP-Fehler: Die Klasse Mock_HttpRequest_a7aa9ffd enthält 4 abstrakte Methoden und muss daher als abstrakt deklariert oder die restlichen Methoden implementiert werden (HttpRequest :: setOption, HttpRequest :: execute, HttpRequest :: getInfo, ...)

13
Tyler Collier

Die Warnung von Tyler Collier ist fair, enthält jedoch keinen Codeausschnitt zum Umgehen des Codes. Beachten Sie, dass dies sehr unangenehm ist und Sie stattdessen die Schnittstelle reparieren sollten. Mit dieser Warnung hinzugefügt:

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