我正在构建ZF2专辑教程应用程序,当我进行单元测试时,即使我再次重建应用程序,我仍然会收到相同的错误。谁能告诉我这里发生了什么?我在这里倾倒所有相关信息以提供帮助。错误是:
PHPUnit 3.7.10 by Sebastian Bergmann.
Configuration read from D:\PHP\zf2-tutorial\module\Album\test\phpunit.xml.dist
......E
Time: 0 seconds, Memory: 6.25Mb
There was 1 error:
1) AlbumTest\Model\AlbumTableTest::testGetAlbumTableReturnsAnInstanceOfAlbumTable
Undefined property: AlbumTest\Model\AlbumTableTest::$controller
D:\PHP\zf2-tutorial\module\Album\test\AlbumTest\Model\AlbumTableTest.php:116
FAILURES!
Tests: 7, Assertions: 9, Errors: 1.
AlbumTableTest.php如下,最终断言收到错误:
<?php
namespace AlbumTest\Model;
use Album\Model\AlbumTable;
use Album\Model\Album;
use Zend\Db\ResultSet\ResultSet;
use PHPUnit_Framework_TestCase;
class AlbumTableTest extends PHPUnit_Framework_TestCase {
public function testFetchAllReturnsAllAlbums() {
$resultSet = new ResultSet();
$mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway', array('select'), array(), '', false);
$mockTableGateway->expects($this->once())
->method('select')
->with()
->will($this->returnValue($resultSet));
$albumTable = new AlbumTable($mockTableGateway);
$this->assertSame($resultSet, $albumTable->fetchAll());
}
public function testCanRetrieveAnAlbumByItsId() {
$album = new Album();
$album->exchangeArray(array('id' => 123,
'artist' => 'The Military Wives',
'title' => 'In My Dreams'));
$resultSet = new ResultSet();
$resultSet->setArrayObjectPrototype(new Album());
$resultSet->initialize(array($album));
$mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway', array('select'), array(), '', false);
$mockTableGateway->expects($this->once())
->method('select')
->with(array('id' => 123))
->will($this->returnValue($resultSet));
$albumTable = new AlbumTable($mockTableGateway);
$this->assertSame($album, $albumTable->getAlbum(123));
}
public function testCanDeleteAnAlbumByItsId() {
$mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway', array('delete'), array(), '', false);
$mockTableGateway->expects($this->once())
->method('delete')
->with(array('id' => 123));
$albumTable = new AlbumTable($mockTableGateway);
$albumTable->deleteAlbum(123);
}
public function testSaveAlbumWillInsertNewAlbumsIfTheyDontAlreadyHaveAnId() {
$albumData = array('artist' => 'The Military Wives', 'title' => 'In My Dreams');
$album = new Album();
$album->exchangeArray($albumData);
$mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway', array('insert'), array(), '', false);
$mockTableGateway->expects($this->once())
->method('insert')
->with($albumData);
$albumTable = new AlbumTable($mockTableGateway);
$albumTable->saveAlbum($album);
}
public function testSaveAlbumWillUpdateExistingAlbumsIfTheyAlreadyHaveAnId() {
$albumData = array('id' => 123, 'artist' => 'The Military Wives', 'title' => 'In My Dreams');
$album = new Album();
$album->exchangeArray($albumData);
$resultSet = new ResultSet();
$resultSet->setArrayObjectPrototype(new Album());
$resultSet->initialize(array($album));
$mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway', array('select', 'update'), array(), '', false);
$mockTableGateway->expects($this->once())
->method('select')
->with(array('id' => 123))
->will($this->returnValue($resultSet));
$mockTableGateway->expects($this->once())
->method('update')
->with(array('artist' => 'The Military Wives', 'title' => 'In My Dreams'), array('id' => 123));
$albumTable = new AlbumTable($mockTableGateway);
$albumTable->saveAlbum($album);
}
public function testExceptionIsThrownWhenGettingNonexistentAlbum() {
$resultSet = new ResultSet();
$resultSet->setArrayObjectPrototype(new Album());
$resultSet->initialize(array());
$mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway', array('select'), array(), '', false);
$mockTableGateway->expects($this->once())
->method('select')
->with(array('id' => 123))
->will($this->returnValue($resultSet));
$albumTable = new AlbumTable($mockTableGateway);
try {
$albumTable->getAlbum(123);
} catch (\Exception $e) {
$this->assertSame('Could not find row 123', $e->getMessage());
return;
}
$this->fail('Expected exception was not thrown');
}
public function testGetAlbumTableReturnsAnInstanceOfAlbumTable() {
$this->assertInstanceOf('Album\Model\AlbumTable', $this->controller->getAlbumTable());
}
}
?>
getAlbumTable在AlbumController中如下:
<?php
namespace Album\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class AlbumController extends AbstractActionController {
protected $albumTable;
public function indexAction() {
return new ViewModel(array(
'albums' => $this->getAlbumTable()->fetchAll(),
));
}
public function addAction() {
}
public function editAction() {
}
public function deleteAction() {
}
public function getAlbumTable() {
if (!$this->albumTable) {
$sm = $this->getServiceLocator();
$this->albumTable = $sm->get('Album\Model\AlbumTable');
}
return $this->albumTable;
}
}
?>
而且AlbumTable是:
<?php
namespace Album\Model;
use Zend\Db\TableGateway\TableGateway;
class AlbumTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}
public function getAlbum($id)
{
$id = (int) $id;
$rowset = $this->tableGateway->select(array('id' => $id));
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
return $row;
}
public function saveAlbum(Album $album)
{
$data = array(
'artist' => $album->artist,
'title' => $album->title,
);
$id = (int)$album->id;
if ($id == 0) {
$this->tableGateway->insert($data);
} else {
if ($this->getAlbum($id)) {
$this->tableGateway->update($data, array('id' => $id));
} else {
throw new \Exception('Form id does not exist');
}
}
}
public function deleteAlbum($id)
{
$this->tableGateway->delete(array('id' => $id));
}
}
?>
Module.php是:
<?php
namespace Album;
class Module
{
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
// Add this method:
public function getServiceConfig()
{
return array(
'factories' => array(
'Album\Model\AlbumTable' => function($sm) {
$tableGateway = $sm->get('AlbumTableGateway');
$table = new AlbumTable($tableGateway);
return $table;
},
'AlbumTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
}
?>
module.config.php是:
<?php
return array(
'controllers' => array(
'invokables' => array(
'Album\Controller\Album' => 'Album\Controller\AlbumController',
),
),
// The following section is new and should be added to your file
'router' => array(
'routes' => array(
'album' => array(
'type' => 'segment',
'options' => array(
'route' => '/album[/:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Album\Controller\Album',
'action' => 'index',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'album' => __DIR__ . '/../view',
),
),
);
?>
application.config.php是:
<?php
return array(
'modules' => array(
'Application',
'Album', // <-- Add this line
),
'module_listener_options' => array(
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
'module_paths' => array(
'./module',
'./vendor',
),
),
);
?>
bootstrap.php中:
<?php
namespace AlbumTest;//Change this namespace for your test
use Zend\Loader\AutoloaderFactory;
use Zend\Mvc\Service\ServiceManagerConfig;
use Zend\ServiceManager\ServiceManager;
use Zend\Stdlib\ArrayUtils;
use RuntimeException;
error_reporting(E_ALL | E_STRICT);
chdir(__DIR__);
class Bootstrap
{
protected static $serviceManager;
protected static $config;
protected static $bootstrap;
public static function init()
{
// Load the user-defined test configuration file, if it exists; otherwise, load
if (is_readable(__DIR__ . '/TestConfig.php')) {
$testConfig = include __DIR__ . '/TestConfig.php';
} else {
$testConfig = include __DIR__ . '/TestConfig.php.dist';
}
$zf2ModulePaths = array();
if (isset($testConfig['module_listener_options']['module_paths'])) {
$modulePaths = $testConfig['module_listener_options']['module_paths'];
foreach ($modulePaths as $modulePath) {
if (($path = static::findParentPath($modulePath)) ) {
$zf2ModulePaths[] = $path;
}
}
}
$zf2ModulePaths = implode(PATH_SEPARATOR, $zf2ModulePaths) . PATH_SEPARATOR;
$zf2ModulePaths .= getenv('ZF2_MODULES_TEST_PATHS') ?: (defined('ZF2_MODULES_TEST_PATHS') ? ZF2_MODULES_TEST_PATHS : '');
static::initAutoloader();
// use ModuleManager to load this module and it's dependencies
$baseConfig = array(
'module_listener_options' => array(
'module_paths' => explode(PATH_SEPARATOR, $zf2ModulePaths),
),
);
$config = ArrayUtils::merge($baseConfig, $testConfig);
$serviceManager = new ServiceManager(new ServiceManagerConfig());
$serviceManager->setService('ApplicationConfig', $config);
$serviceManager->get('ModuleManager')->loadModules();
static::$serviceManager = $serviceManager;
static::$config = $config;
}
public static function getServiceManager()
{
return static::$serviceManager;
}
public static function getConfig()
{
return static::$config;
}
protected static function initAutoloader()
{
$vendorPath = static::findParentPath('vendor');
if (is_readable($vendorPath . '/autoload.php')) {
$loader = include $vendorPath . '/autoload.php';
} else {
$zf2Path = getenv('ZF2_PATH') ?: (defined('ZF2_PATH') ? ZF2_PATH : (is_dir($vendorPath . '/ZF2/library') ? $vendorPath . '/ZF2/library' : false));
if (!$zf2Path) {
throw new RuntimeException('Unable to load ZF2. Run `php composer.phar install` or define a ZF2_PATH environment variable.');
}
include $zf2Path . '/Zend/Loader/AutoloaderFactory.php';
}
AutoloaderFactory::factory(array(
'Zend\Loader\StandardAutoloader' => array(
'autoregister_zf' => true,
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/' . __NAMESPACE__,
),
),
));
}
protected static function findParentPath($path)
{
$dir = __DIR__;
$previousDir = '.';
while (!is_dir($dir . '/' . $path)) {
$dir = dirname($dir);
if ($previousDir === $dir) return false;
$previousDir = $dir;
}
return $dir . '/' . $path;
}
}
Bootstrap::init();
?>
TestConfig.php.dist:
<?php
return array(
'modules' => array(
'Album',
),
'module_listener_options' => array(
'config_glob_paths' => array(
'../../../config/autoload/{,*.}{global,local}.php',
),
'module_paths' => array(
'module',
'vendor',
),
),
);
?>
最后,phpunit.xml.dist:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="Bootstrap.php">
<testsuites>
<testsuite name="zf2tutorial">
<directory>./AlbumTest</directory>
</testsuite>
</testsuites>
</phpunit>
答案 0 :(得分:3)
您认为需要添加一些设置代码并将其与AlbumControllerTest.php
进行比较是正确的,这是正确的。
正如错误消息所述,问题是AlbumTableTest
对象没有controller
属性。因此,我们需要使用以下方法添加属性:
$protected controller
并使用以下内容对其进行初始化:
$this->controller = new AlbumController()
此外,我们需要初始化serviceManager
属性并设置其serviceLocator
属性,以便以下调用在控制器的getAlbumTable
方法中有意义:
$sm = $this->getServiceLocator();
$this->albumTable = $sm->get('Album\Model\AlbumTable');
总结一下,你做了正确的事,但你不需要所有额外的代码。你可以逃脱:
use AlbumTest\Bootstrap;
use Album\Controller\AlbumController;
use Album\Model\AlbumTable;
use Album\Model\Album;
use Zend\Db\ResultSet\ResultSet;
use PHPUnit_Framework_TestCase;
class AlbumTableTest extends PHPUnit_Framework_TestCase
{
protected $controller;
protected function setUp()
{
$serviceManager = Bootstrap::getServiceManager();
$this->controller = new AlbumController();
$this->controller->setServiceLocator($serviceManager);
}
....
在AlbumTableTest.php
答案 1 :(得分:2)
虽然我不确定这是否是适当的解决方案,但我解决了错误。我查看了AlbumControllerTest而不是AlbumTableTest。它有一个创建控制器类的安装方法。我复制了设置代码以及相应的use语句和变量声明,目前我正在研究下一期......
我仍然对更好的答案感兴趣!
我复制(添加)的内容包括:
use AlbumTest\Bootstrap;
use Album\Controller\AlbumController;
use Zend\Http\Request;
use Zend\Http\Response;
use Zend\Mvc\MvcEvent;
use Zend\Mvc\Router\RouteMatch;
use Zend\Mvc\Router\Http\TreeRouteStack as HttpRouter;
use PHPUnit_Framework_TestCase;
class AlbumTableTest extends PHPUnit_Framework_TestCase {
protected $controller;
protected $request;
protected $response;
protected $routeMatch;
protected $event;
protected function setUp()
{
$serviceManager = Bootstrap::getServiceManager();
$this->controller = new AlbumController();
$this->request = new Request();
$this->routeMatch = new RouteMatch(array('controller' => 'index'));
$this->event = new MvcEvent();
$config = $serviceManager->get('Config');
$routerConfig = isset($config['router']) ? $config['router'] : array();
$router = HttpRouter::factory($routerConfig);
$this->event->setRouter($router);
$this->event->setRouteMatch($this->routeMatch);
$this->controller->setEvent($this->event);
$this->controller->setServiceLocator($serviceManager);
}
答案 2 :(得分:0)
您忘记在Module.php中添加新的import语句。文件的开头应如下所示:
namespace Album;
use Album\Model\Album;
use Album\Model\AlbumTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
class Module
{
//...
容易跳过,很难找到,我在同样的事情上花了15分钟......