Domanda

Sto provando a testare una classe che gestisce l'accesso ai dati nel database (sai, CRUD, essenzialmente). La libreria DB che stiamo utilizzando ha un'API in cui per prima cosa ottieni l'oggetto table tramite una chiamata statica:

function getFoo($id) {
  $MyTableRepresentation = DB_DataObject::factory("mytable");
  $MyTableRepresentation->get($id);
  ... do some stuff
  return $somedata
}

... hai avuto l'idea.

Stiamo provando a testare questo metodo, ma prendendo in giro le cose di DataObject in modo che (a) non abbiamo bisogno di una connessione db effettiva per il test e (b) non abbiamo nemmeno bisogno di includere la lib DB_DataObject per il test.

Tuttavia, in PHPUnit non riesco a ottenere $ this- > getMock () per impostare correttamente una chiamata statica. Ho ...

        $DB_DataObject = $this->getMock('DB_DataObject', array('factory'));

... ma il test dice ancora un metodo sconosciuto "factory". So che sta creando l'oggetto, perché prima che dicesse non riusciva a trovare DB_DataObject. Adesso può. Ma nessun metodo?

Quello che voglio davvero fare è avere due oggetti finti, uno anche per l'oggetto tabella restituito. Quindi, non solo devo specificare che factory è una chiamata statica, ma anche che restituisce alcuni altri oggetti similari che ho già impostato.

Dovrei menzionare come avvertimento che ho fatto questo in SimpleTest qualche tempo fa (non riesco a trovare il codice) e ha funzionato bene.

Cosa dà?

[UPDATE]

Sto cominciando a capire che ha qualcosa a che fare con aspettative ()

È stato utile?

Soluzione

Sono d'accordo con entrambi che sarebbe meglio non usare una chiamata statica. Tuttavia, immagino di aver dimenticato di menzionare che DB_DataObject è una libreria di terze parti e che la chiamata statica è la loro best practice per l'utilizzo del codice, non la nostra. Esistono altri modi per utilizzare i loro oggetti che implicano la costruzione diretta dell'oggetto restituito. Lascia solo quelle dannose istruzioni include / request in qualunque file di classe utilizzi quella classe DB_DO. Questo fa schifo perché i test si interromperanno (o semplicemente non saranno isolati) se nel frattempo stai provando a deridere una classe con lo stesso nome nel tuo test - almeno credo.

Altri suggerimenti

Quando non è possibile modificare la libreria, modificarne l'accesso. Rifattorizza tutte le chiamate a DB_DataObject :: factory () in un metodo di istanza nel tuo codice:

function getFoo($id) {
  $MyTableRepresentation = $this->getTable("mytable");
  $MyTableRepresentation->get($id);
  ... do some stuff
  return $somedata
}

function getTable($table) {
  return DB_DataObject::factory($table);
}

Ora puoi usare un mock parziale della classe che stai testando e getTable () restituisce un oggetto tabella mock.

function testMyTable() {
  $dao = $this->getMock('MyTableDao', array('getMock'));
  $table = $this->getMock('DB_DataObject', ...);
  $dao->expects($this->any())
      ->method('getTable')
      ->with('mytable')
      ->will($this->returnValue($table));
  $table->expects...
  ...test...
}

Questo è un buon esempio di dipendenza nel tuo codice - il design ha reso impossibile iniettare in un Mock piuttosto che nella classe reale.

Il mio primo suggerimento sarebbe di provare a refactificare il codice per usare un'istanza piuttosto che una chiamata statica.

Cosa manca (o no?) alla tua classe DB_DataObject è un setter per passare un oggetto db preparato prima di chiamare il metodo factory. In questo modo puoi passare un oggetto db o personalizzato (con la stessa interfaccia) in caso di necessità.

Nella configurazione del test:

 public function setUp() {
      $mockDb = new MockDb();
      DB_DataObject::setAdapter($mockDb);
 }

Il metodo factory () dovrebbe restituire l'istanza DB derisa. Se non è già integrato nella tua classe, probabilmente dovrai rifattorizzare anche il metodo factory () per farlo funzionare.

È necessario / incluso il file di classe per DB_DataObject nel test case? Se la classe non esiste prima che PHPUnit provi a deridere l'oggetto, puoi ottenere errori come questo.

Con l'estensione PHPUnit MockFunction più runkit puoi anche deridere metodi statici. Fai attenzione, perché è il patching delle scimmie e quindi dovrebbe essere usato solo in casi estremi. Non sostituisce le buone pratiche di programmazione.

https://github.com/tcz/phpunit-mockfunction

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