2012-09-26 4 views
16

Sono nuovo al test delle unità e PHPUnit.Metodo non definito sull'oggetto mock che implementa una determinata interfaccia in PHPUnit?

Ho bisogno di una simulazione, su cui ho il controllo completo, che implementa l'interfaccia ConfigurationInterface. L'oggetto del test è l'oggetto ReportEventParamConverter e il test deve verificare l'interazione tra il mio oggetto e l'interfaccia.

ReportEventParamConverter oggetto (qui semplificata):

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

E questo è il modo in cui sto cercando di deridere l'interfaccia:

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

ho bisogno di simulare i valori restituiti per due metodi: getClass() e getName(). Per esempio:

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

quando creo un nuovo metodo di ReportEventParamConverter e di prova supports(), ottengo il seguente errore PHPUnit:

Fatal error: Call to undefined method Mock_ConfigurationInterface_21e9dccf::getClass().

$converter = new ReportEventParamConverter(); 
$this->assertFalse($converter->supports($mock)); 
+0

Il parametro "ParamConverterInterface" ha il metodo 'getClass()'? – hakre

+0

@hakra importa? – gremo

+0

Rispondi alla domanda per aggiungere ulteriori informazioni alla tua domanda. Ciò avrebbe importanza. A parte questo, sarebbe la mia prima ipotesi sul perché la simulazione non abbia quella funzione. Quindi alcuni debug di base. – hakre

risposta

18

è perché non v'è alcuna dichiarazione di metodo "getClass" in ConfigurationInterface. L'unica dichiarazione in questa interfaccia è il metodo "getAliasName".

Tutto ciò che serve è quello di dire che cosa metodi mock verrà STUBING:

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

Si noti che non v'è alcuna dichiarazione "getClass" ma è possibile stub/finto metodo non esistenti. Perciò si può deridere esso:

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

Ma in addtion è necessario prendere in giro "getAliasName" metodo, così come fino a quando è il metodo di interfaccia o un astratto e deve essere "implementato". Es .:

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

Quindi se i metodi non esistono nella classe originale dovrebbe essere dichiarato nella chiamata 'getMock()' Se il metodo esiste allora non è necessario? – gremo

+3

Dovresti sempre dire a quali metodi stai andando a stub/mock Se non lo specifichi, il mock supponete che stub tutti i metodi dalla classe (per esempio se specificate solo un metodo methodA, $ mock = $ this-> getMock ('Class', array ('metodoA')), il mock presume che vi prendiate in giro SOLO methodA, e quando chiami un altro metodo: $ mock-> methodB(), allora viene eseguito il metodo "reale" da "Class") – Cyprian

+0

Grazie! Funziona ora. – gremo

12

La risposta di Cyprian mi ha aiutato, ma c'è una cosa da sapere. Puoi prendere in giro classi che non esistono e PHPUnit non si lamenterà. Così si potrebbe fare

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

Questo significa che se ConfigurationInterface non esiste in quel punto durante il runtime, ci si può comunque ottenere un messaggio come

Fatal error: Call to undefined method Mock_ConfigurationInterface_21e9dccf::getClass().

Se sei sicuro il metodo davvero esiste sulla classe, quindi il probabile problema è che la classe stessa non esiste (perché non l'hai richiesta, o l'hai scritta male, ecc.).


L'OP utilizza un'interfaccia .Sappiate che è necessario chiamare getMock senza specificare la lista dei metodi per ignorare, o se lo fai, è necessario passare array(), oppure passare tutti i nomi dei metodi, o si otterrà un errore simile al seguente:

PHP Fatal error: Class Mock_HttpRequest_a7aa9ffd contains 4 abstract methods and must therefore be declared abstract or implement the remaining methods (HttpRequest::setOption, HttpRequest::execute, HttpRequest::getInfo, ...)

+2

Grazie per aver menzionato questo, era davvero una classe mancante che era causandomi problemi – ChiperSoft

+0

Grazie. H ad lo stesso problema. – Mantas

+0

L'ho sperimentato mentre prendevo in giro una libreria esterna che era 'require'd nella classe sotto test, ma non conforme al caricatore automatico. –

1

L'avviso di Tyler Collier è corretto ma non contiene uno snippet di codice su come codificarlo. Nota che questo è molto brutto e dovresti invece correggere l'interfaccia. A questo avviso aggiunto:

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