Sto assemblando una serie di modelli da utilizzare in un'applicazione Zend Framework 2. Quindi, ogni modello ha una classe di tabella che funge da interfaccia tra il modello e il database per l'interrogazione. Utilizzando lo ZF2% diTableGateway
significa che anche una query abbastanza semplice, come ottenere il numero di risultati da un log di pagina tra due date, finisce con alcune chiamate complesse:
public function getDailyHits($start, $end)
{
$select = $this->tableGateway->getSql()->select();
$select->columns(array(
"date" => new Expression("DATE_FORMAT(timestamp, '%Y-%m-%d')"),
"hits" => new Expression("COUNT(timestamp)"),
));
$select->where->between("timestamp", $start, $end);
$select->group("date");
$results = $this->tableGateway->selectWith($select);
$dailyHits = array();
foreach ($results as $result) {
$dailyHits[$result->date] = $result->hits;
}
return $dailyHits;
}
Quando si è trattato di sviluppare il test unitario, ho scritto un sacco di aspettative:
public function testGetDailySearches()
{
// Setup
$result = new \stdClass();
$result->date = "2015-01-01";
$result->searches = 42;
$resultSet = array($result);
$sql = $this->getMockBuilder("Zend\Db\Sql\Sql")
->disableOriginalConstructor()
->getMock();
$select = $this->getMockBuilder("Zend\Db\Sql\Select")
->disableOriginalConstructor()
->getMock();
$where = $this->getMockBuilder("Zend\Db\Sql\Where")
->disableOriginalConstructor()
->getMock();
$tableGateway = $this->getMockBuilder("Zend\Db\TableGateway\TableGateway")
->disableOriginalConstructor()
->getMock();
$searchLogTable = $this->getMockBuilder("Usage\Model\Table\SearchLog")
->setConstructorArgs(array($tableGateway))
->setMethods(null)
->getMock();
// Expectations
$tableGateway->expects($this->once())
->method("getSql")
->will($this->returnValue($sql));
$tableGateway->expects($this->once())
->method("selectWith")
->with($this->equalTo($select))
->will($this->returnValue($resultSet));
$sql->expects($this->once())
->method("select")
->will($this->returnValue($select));
$select->expects($this->once())
->method("columns")
->will($this->returnValue($select)); // TODO: need to assert parameters
$select->expects($this->once())
->method("__get")
->with($this->equalTo("where"))
->will($this->returnValue($where));
$where->expects($this->once())
->method("between")
->with(
$this->equalTo("time"),
$this->equalTo("2015-10-01 00:00:00"),
$this->equalTo("2015-10-07 23:59:59")
)
->will($this->returnValue($select));
$select->expects($this->once())
->method("group")
->with($this->equalTo("date"));
// Assertions
$this->assertEquals(
array("2015-01-01" => 42),
$searchLogTable->getDailySearches("2015-10-01 00:00:00", "2015-10-07 23:59:59")
);
}
Ho provato a usare Prophecy per ridurre la verbosità in questi test, ma sono stato inciampato con loro mag% __get
metodo necessario per leggere la proprietà $ dove di Select oggetto.
Dopo aver letto un paio di thread sul sito di Prophecy, ho scoperto un link a > That not Notours" . Ha molto senso. Inoltre, in alcuni test ridurrebbe un sacco di file standard se eseguo la sottoclasse di TableGateway (o forse anche solo la derisione) in modo che tutto il comportamento di Zend \ Db venga mantenuto.
Ma allora cosa succede alle mie aspettative? È un caso di test eccessivamente ingegnerizzati? Devo avere queste aspettative, o dovrei fare affidamento sul test di una scatola per lo più nera di un metodo?
Se rimuovevo quelle aspettative, e facevo affidamento su un risultato deriso da selectWith sottoclasse / deriso, potevo scrivere un test di passaggio che non specificava nessuno dei criteri di selezione, e non funzionava come richiesto nel reale mondo.