Domanda

Per gli oggetti che compongono un altro oggetto, come parte della loro attuazione, qual è il modo migliore per scrivere il test di unità in modo che solo l'oggetto principio viene testato? Esempio banale:

class myObj { 
    public function doSomethingWhichIsLogged()
    {
        // ...
        $logger = new logger('/tmp/log.txt');
        $logger->info('some message');
        // ...
    }
}

So che l'oggetto potrebbe essere progettato in modo tale che la dipendenza oggetto logger potrebbe essere iniettato e, quindi, preso in giro in un test di unità, ma non è sempre il caso - in scenari più complessi, si ha bisogno di comporre altri oggetti o effettuare chiamate a metodi statici.

Come noi non vogliamo testare l'oggetto logger, solo il myObj, come procediamo? Si fa a creare un contuso "doppio" con lo script di test? Qualcosa di simile:

class logger
{
    public function __construct($filepath) {}
    public function info($message) {}
}

class TestMyObj extends PHPUnit_Framework_TestCase 
{
    // ...
}

Questo sembra fattibile per piccoli oggetti, ma sarebbe un dolore per le API più complesse dove il SUT dipendeva dai valori di ritorno. Inoltre, cosa succede se si desidera verificare le chiamate all'oggetto di dipendenza nello stesso stato è possibile con oggetti fittizi? C'è un modo di beffardo oggetti che sono istanziati dal SUT anziché essere passato nel?

Ho letto la pagina man su schernisce, ma non sembra per coprire questa situazione in cui la dipendenza è composto piuttosto che aggregata. Come si fa a farlo?

È stato utile?

Soluzione

Come ti sembra di essere a conoscenza già, Calcestruzzo Classe Dipendenze rende il test difficile (o addirittura impossibile). È necessario disaccoppiare tale dipendenza. Un cambiamento semplice, che non si rompe l'API esistente, è per difetto al comportamento corrente, ma fornire un gancio per scavalcarlo. Ci sono un certo numero di modi in cui questo potrebbe essere attuato.

Alcune lingue dispongono di strumenti in grado di iniettare classi finte in codice, ma non so nulla di simile per PHP. Nella maggior parte dei casi, si sarebbe probabilmente essere meglio refactoring il codice in ogni caso.

Altri suggerimenti

Dopo troelskn consigliare ecco un esempio di base di ciò che si dovrebbe fare.

<?php

class MyObj
{
    /**
     * @var LoggerInterface
     */
    protected $_logger;

    public function doSomethingWhichIsLogged()
    {
        // ...
        $this->getLogger()->info('some message');
        // ...
    }

    public function setLogger(LoggerInterface $logger)
    {
        $this->_logger = $logger;
    }

    public function getLogger()
    {
        return $this->_logger;
    }
}


class MyObjText extends PHPUnit_Framework_TestCase
{
    /**
     * @var MyObj
     */
    protected $_myObj;

    public function setUp()
    {
        $this->_myObj = new MyObj;
    }

    public function testDoSomethingWhichIsLogged()
    {
        $mockedMethods = array('info');
        $mock = $this->getMock('LoggerInterface', $mockedMethods);
        $mock->expects($this->any())
             ->method('info')
             ->will($this->returnValue(null));

        $this->_myObj->setLogger($mock);

        // do your testing
    }
}

Maggiori informazioni su oggetti mock può essere trovato rel="noreferrer"> .

Non è in realtà un ragionevolmente nuova estensione per la classe PHP sovraccarico rilasciato dagli stessi ragazzi che costruiscono PHPUnit. Esso consente di sostituire il nuovo operatore nei casi in cui non è possibile refactoring del codice, purtroppo non è così semplice da installare su Windows.

L'URL è http://github.com/johannes/php -test-aiutanti / blob / master /

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top