Zacząłem uczyć się Zend Framework kilka lat temu po this tutorial. Tam pokazuje, że mappers są tworzone przy użyciu klasy Zend\Db\Adapter\Adapter
, aby uzyskać połączenie z bazą danych i tak pracowałem z bazami danych, ponieważ bez problemów.Zend Framework 2 i PHPUnit - podszywając się pod Zend Db Adapter Adapter class
Teraz próbuję nauczyć się korzystać z PHPUnit na aplikacjach Zend i mam problemy z testowaniem funkcji w programie odwzorowującym, ponieważ nie jestem w stanie sfałszować klasy Zend\Db\Adapter\Adapter
.
This tutorial na stronie Zend pokazuje kpiny z połączeń z bazami danych, ale używa klasy Zend\Db\TableGateway\TableGateway
. Wszystkie inne samouczki znalazłem w Internecie użyć tej klasy także, a jedyną rzeczą, jaką znalazłem w odniesieniu do klasy Zend\Db\Adapter\Adapter
jest this:
$date = new DateTime();
$mockStatement = $this->getMock('Zend\Db\Adapter\Driver\Pdo\Statement');
$mockStatement->expects($this->once())->method('execute')->with($this->equalTo(array(
'timestamp' => $date->format(FormatterInterface::DEFAULT_DATETIME_FORMAT)
)));
$mockDbDriver = $this->getMockBuilder('Zend\Db\Adapter\Driver\Pdo\Pdo')
->disableOriginalConstructor()
->getMock();
$mockDbAdapter = $this->getMock('Zend\Db\Adapter\Adapter', array(), array($mockDbDriver));
$mockDbAdapter->expects($this->once())
->method('query')
->will($this->returnValue($mockStatement));
Próbowałem oddanie że do mojego sposobu setUp
ale działa na phpunit
Klasa testu daje mi następujący błąd:
Fatal error: Call to a member function createStatement() on null in C:\Program Files (x86)\Zend\Apache2\htdocs\test_project\vendor\zendframework\zend-db\src\Sql\Sql.php on line 128
Więc moje pytanie jest, w jaki sposób mock klasy w PHPUnit Zend\Db\Adapter\Adapter
?
Widziałem this question, który jest podobny, ale zamiast tego używa Zend/Db/Adapter/AdapterInterface
i nie mogę przetłumaczyć tego kodu na moją sytuację. Mapper i kod klasy testu poniżej.
ProductMapper.php:
public function __construct(Adapter $dbAdapter) {
$this->dbAdapter = $dbAdapter;
$this->sql = new Sql($dbAdapter);
}
public function fetchAllProducts() {
$select = $this->sql->select('products');
$statement = $this->sql->prepareStatementForSqlObject($select);
$results = $statement->execute();
$hydrator = new ClassMethods();
$product = new ProductEntity();
$resultset = new HydratingResultSet($hydrator, $product);
$resultset->initialize($results);
$resultset->buffer();
return $resultset;
}
ProductMapperTest.php:
public function setUp() {
$date = new DateTime();
$mockStatement = $this->getMock('Zend\Db\Adapter\Driver\Pdo\Statement');
$mockStatement->expects($this->once())->method('execute')->with($this->equalTo(array(
'timestamp' => $date->format(FormatterInterface::DEFAULT_DATETIME_FORMAT)
)));
$mockDbDriver = $this->getMockBuilder('Zend\Db\Adapter\Driver\Pdo\Pdo')->disableOriginalConstructor()->getMock();
$this->mockDbAdapter = $this->getMock('Zend\Db\Adapter\Adapter', array(), array(
$mockDbDriver
));
$this->mockDbAdapter->expects($this->once())->method('query')->will($this->returnValue($mockStatement));
}
public function testFetchAllProducts() {
$resultsSet = new ResultSet();
$productMapper = new ProductMapper($this->mockDbAdapter);
$this->assertSame($resultsSet, $productMapper->fetchAllProducts());
}
EDIT # 1:
Obserwuj ing dalej od odpowiedzi Wilt za zmieniłem mapowania użyć klasy Sql
w konstruktorze i zmieniłem klasę testową do:
public function setUp() {
$mockSelect = $this->getMock('Zend\Db\Sql\Select');
$mockDbAdapter = $this->getMockBuilder('Zend\Db\Adapter\AdapterInterface')->disableOriginalConstructor()->getMock();
$this->mockStatement = $this->getMock('Zend\Db\Adapter\Driver\Pdo\Statement');
$this->mockSql = $this->getMock('Zend\Db\Sql\Sql', array('select', 'prepareStatementForSqlObject'), array($mockDbAdapter));
$this->mockSql->method('select')->will($this->returnValue($mockSelect));
$this->mockSql->method('prepareStatementForSqlObject')->will($this->returnValue($this->mockStatement));
}
public function testFetchAllProducts() {
$resultsSet = new ResultSet();
$this->mockStatement->expects($this->once())->method('execute')->with()->will($this->returnValue($resultsSet));
$productMapper = new ProductMapper($this->mockSql);
$this->assertSame($resultsSet, $productMapper->fetchAllProducts());
}
Ja jednak teraz pojawia się następujący błąd:
ProductTest\Model\ProductMapperTest::testFetchAllProducts Failed asserting that two variables reference the same object.
Która jest pochodzące z linii $this->assertSame($resultsSet, $productMapper->fetchAllProducts());
. Czy wyśmiałem coś niepoprawnie?
Edit # 2:
Jak sugeruje Wilt, zmieniłem klasę testową użyć StatementInterface
drwić oświadczenie zamiast, więc kod teraz wygląda:
public function setUp() {
$mockSelect = $this->getMock('Zend\Db\Sql\Select');
$mockDbAdapter = $this->getMockBuilder('Zend\Db\Adapter\AdapterInterface')->disableOriginalConstructor()->getMock();
$this->mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface');
$this->mockSql = $this->getMock('Zend\Db\Sql\Sql', array('select', 'prepareStatementForSqlObject'), array($mockDbAdapter));
$this->mockSql->method('select')->will($this->returnValue($mockSelect));
$this->mockSql->method('prepareStatementForSqlObject')->will($this->returnValue($this->mockStatement));
}
public function testFetchAllProducts() {
$resultsSet = new ResultSet();
$this->mockStatement->expects($this->once())->method('execute')->with()->will($this->returnValue($resultsSet));
$productMapper = new ProductMapper($this->mockSql);
$this->assertSame($resultsSet, $productMapper->fetchAllProducts());
}
Ale przypadek testowy nadal nie działa tak, jak powyżej. Nie zmieniłem linii kodu, która kpi z metody execute
, ponieważ uważam, że już powraca $resultsSet
, ale mogę się mylić!
Świetna odpowiedź dzięki, skierowała mnie we właściwym kierunku, zmieniając zależność, aby użyć instancji 'Sql'. Teraz pozbyłem się komunikatu o błędzie, ale sam test kończy się niepowodzeniem tam, gdzie oczekiwałbym tego. Dodałem nowy kod do pytania, czy nie miałbyś nic przeciwko temu, by rzucić okiem? Nie jestem pewien, czy wyśmiałam coś źle, czy jest to po prostu mój brak doświadczenia w testach jednostkowych i błędnie zakładam, że test przejdzie! – crazyloonybin
@ Crazyloonybin Wystarczy użyć "StatementInterface", aby wyśmiać instrukcję (nie ma potrzeby, aby w tym celu była wymagana określona klasa adaptera). Następnie musisz wyśmiewać metodę 'execute' w tym' $ mockStatement', a wartość zwracana tej metody powinna być '$ resultsSet'. Następnie twój test powinien przejść. – Wilt
Zmieniono instrukcję, aby przeczytać '$ this-> mockStatement = $ this-> getMock ('Zend \ Db \ Adapter \ Driver \ StatementInterface');' ale nadal otrzymuję ten sam błąd. Zachowałem kod '$ this-> mockStatement' taki sam jak to, co pokazano w edycji pytania, z funkcją' testFetchAllProducts' zwracającą '$ resultsSet' - czy ta linia również wymaga modyfikacji? – crazyloonybin