下面我将尽可能如实记录实践这个项目的每一个步骤,因为有些步骤在一般情况下是可选的,但在本次实践中可能会因为省略了这些步骤引起前后不一致。
一、修改入口文件:
Zend Framework的单一入口就是index.php文件,默认的文件很简练紧凑,不需要做大幅修改,但我还是对它进行了一点改动。
为了在后续的所有文件中都能有一个相对固定的引用文件的起点,以免在不同的文件中使用相对路径引用文件时迷路,我指定了一个常量,用来指向整个项目的根文件夹,这个常量被命名为ROOT_PATH。后面所有使用相对路径的地方都改成以此为参照的绝对路径引用。
为了使整个程序易于移植,这个常量的定义使用了如下方式:
define ('ROOT_PATH', dirname(dirname(__FILE__)));
|
header('Content-Type:text/html; charset=utf8');
|
使用了 Zend Framework 1.5 的布局模式
require_once 'Zend/Layout.php';
|
Zend_Layout::startMvc(array(
'layoutPath' => '../application/default/layouts',
'layout' => 'main'
));
|
完整的入口文件:
index.php
<?php
/**
* My new Zend Framework project
*
* @author lxw(matchless.liu@gmail.com)
* @version SVN $Id: index.php 28 2008-07-23 14:27:42Z lxw $
*/
define ('ROOT_PATH', dirname(dirname(__FILE__)));
set_include_path(ROOT_PATH . '/library' . PATH_SEPARATOR . ROOT_PATH . '/application' . PATH_SEPARATOR . get_include_path());
require_once 'Zend/Controller/Front.php';
require_once 'Zend/Layout.php';
header("Content-Type:text/html;charset=utf8");
/**
* Setup controller
*/
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory(array(ROOT_PATH . '/application/default/controllers'));
$controller->throwExceptions(false); // should be turned on in development time
// bootstrap layouts
Zend_Layout::startMvc(array(
'layoutPath' => '../application/default/layouts',
'layout' => 'main'
));
// run!
$controller->dispatch();
|
二、第一个单元测试
既然是测试驱动开发,当然是要写单元测试了。
现在还什么都没有,只有一个IndexController,其中也没有model,不过要先写一个测试,看看测试文件都需要写些什么才能跑得起来。
这个测试是针对IndexController的,按照之前的路径约定,它应该放在tests/application/default/controllers文件夹中,命名为IndexControllerTest.php,并根据类名约定命名类。
IndexControllerTest.php
<?php
require_once dirname(dirname(dirname(dirname(__FILE__)))) . '/TestHelper.php';
require_once 'default/controllers/IndexController.php';
class IndexControllerTest extends PHPUnit_Framework_TestCase
{
public function testIndexAction()
{
require_once("Zend/Session.php");
Zend_Session::start();
require_once('Zend/Controller/Front.php');
require_once ('Zend/Controller/Request/Http.php');
require_once ('Zend/Controller/Response/Http.php');
require_once 'Zend/Controller/Router/Rewrite.php';
$front = Zend_Controller_Front::getInstance();
$request = new Zend_Controller_Request_Http();
$response = new Zend_Controller_Response_Http();
$front->setRequest($request);
$controller = new IndexController($request, $response);
$controller->indexAction();
}
}
|
其中TestHelper.php中是每次测试都需要指定的include_path及对测试框架文件的require。它被放置在tests文件夹中。
TestHelper.php
<?php
/**
* Ebuyhotel
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
*
* @category Ebuyhotel
* @package UnitTests
* @copyright Copyright (c) 2008-2008 lxw (matchless.liu@gmail.com)
* @version $Id: TestHelper.php 44 2008-09-24 13:52:15Z lxw $
*/
/*
* Start output buffering
*/
ob_start();
/*
* Include PHPUnit dependencies
*/
require_once 'PHPUnit/Framework.php';
require_once 'PHPUnit/Framework/IncompleteTestError.php';
require_once 'PHPUnit/Framework/TestCase.php';
require_once 'PHPUnit/Framework/TestSuite.php';
require_once 'PHPUnit/Runner/Version.php';
require_once 'PHPUnit/TextUI/TestRunner.php';
require_once 'PHPUnit/Util/Filter.php';
/*
* Set error reporting to the level to which Ebuyhotel code must comply.
*/
error_reporting( E_ALL | E_STRICT );
/*
* Determine the root, library, and tests directories of the framework
* distribution.
*/
$EbuyhotelRoot = dirname(dirname(__FILE__));
$EbuyhotelTests = "$EbuyhotelRoot/tests";
$EbuyhotelTestsApplication = "$EbuyhotelTests/application";
$EbuyhotelTestsLibrary = "$EbuyhotelTests/library";
$EbuyhotelApplication = "$EbuyhotelRoot/application";
$EbuyhotelLibray = "$EbuyhotelRoot/library";
/*
* Omit from code coverage reports the contents of the tests directory
*/
foreach (array('php', 'phtml', 'csv') as $suffix) {
PHPUnit_Util_Filter::addDirectoryToFilter($EbuyhotelTests, ".$suffix");
}
/*
* Prepend the Ebuyhotel library/ and application/ and tests/ directories to the
* include_path. This allows the tests to run out of the box and helps prevent
* loading other copies of the framework code and tests that would supersede
* this copy.
*/
$path = array(
$EbuyhotelTests,
$EbuyhotelTestsApplication,
$EbuyhotelTestsLibrary,
$EbuyhotelApplication,
$EbuyhotelLibray,
get_include_path()
);
set_include_path(implode(PATH_SEPARATOR, $path));
/*
* Load the user-defined test configuration file, if it exists; otherwise, load
* the default configuration.
*/
if (is_readable($EbuyhotelTests . DIRECTORY_SEPARATOR . 'TestConfiguration.php')) {
require_once $EbuyhotelTests . DIRECTORY_SEPARATOR . 'TestConfiguration.php';
} else {
require_once $EbuyhotelTests . DIRECTORY_SEPARATOR . 'TestConfiguration.php.dist';
}
/*
* Unset global variables that are no longer needed.
*/
unset($EbuyhotelRoot, $EbuyhotelApplication, $EbuyhotelLibray, $EbuyhotelTests, $EbuyhotelTestsApplication, $EbuyhotelTestsLibrary, $path);
|
运行一下测试文件:右击IndexControllerTest.php,选择快捷菜单中的Run as>3.PHPUnit Test
结果如下图
测试结果很直观,好看,功能也挺强,就是有点慢。
在跑测试的时候会测试代码覆盖率,还会以xml文件的格式记录测试结果,好像不是每次都有必要,为了速度,可以先关掉它:Window>Preferences,选择PHP>PHPUnit,清除Collect Code Coverage statistics和Generate XML report复选框。这可以加快测试的速度。
改成能用PHP直接运行的就更好了!说干就干,参考Zend Framework自己的测试,修改结果如下:
IndexControllerTest.php
<?php
require_once dirname(dirname(dirname(dirname(__FILE__)))) . '/TestHelper.php';
require_once 'default/controllers/IndexController.php';
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD','IndexController_AllTests::main');
}
class IndexController_AllTests
{
static public function main()
{
PHPUnit_TextUI_TestRunner::run(self::suite());
}
static public function suite()
{
$testSuite = new PHPUnit_Framework_TestSuite('IndexController AllTests');
$testSuite->addTestSuite('IndexControllerTest');
return $testSuite;
}
}
class IndexControllerTest extends PHPUnit_Framework_TestCase
{
public function testIndexAction()
{
require_once("Zend/Session.php");
Zend_Session::start();
require_once('Zend/Controller/Front.php');
require_once ('Zend/Controller/Request/Http.php');
require_once ('Zend/Controller/Response/Http.php');
require_once 'Zend/Controller/Router/Rewrite.php';
$front = Zend_Controller_Front::getInstance();
$request = new Zend_Controller_Request_Http();
$response = new Zend_Controller_Response_Http();
$front->setRequest($request);
$controller = new IndexController($request, $response);
$controller->indexAction();
}
}
if (PHPUnit_MAIN_METHOD == 'IndexController_AllTests::main') {
IndexController_AllTests::main();
}
|
右击IndexControllerTest.php,选择快捷菜单中的Run as>1. PHP Script,结果如下图:
不过这个测试可就不能以PHPUnit Test的方式运行了。
再改改,参考Zend Framework的测试套件的写法。
IndexControllerTest.php
<?php
require_once dirname(dirname(dirname(dirname(__FILE__)))) . '/TestHelper.php';
require_once 'default/controllers/IndexController.php';
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD','IndexController_AllTests::main');
}
class IndexController_AllTests extends PHPUnit_Framework_TestSuite
{
static public function main()
{
PHPUnit_TextUI_TestRunner::run(self::suite());
}
public function __construct()
{
$this->setName('IndexController_AllTests');
$this->addTestSuite('IndexControllerTest');
}
static public function suite()
{
return new self();
}
}
class IndexControllerTest extends PHPUnit_Framework_TestCase
{
public function testIndexAction()
{
require_once("Zend/Session.php");
Zend_Session::start();
require_once('Zend/Controller/Front.php');
require_once ('Zend/Controller/Request/Http.php');
require_once ('Zend/Controller/Response/Http.php');
require_once 'Zend/Controller/Router/Rewrite.php';
$front = Zend_Controller_Front::getInstance();
$request = new Zend_Controller_Request_Http();
$response = new Zend_Controller_Response_Http();
$front->setRequest($request);
$controller = new IndexController($request, $response);
$controller->indexAction();
}
}
if (PHPUnit_MAIN_METHOD == 'IndexController_AllTests::main') {
IndexController_AllTests::main();
}
|
以PHPUnit Test方式运行的结果如下图:
咦,怎么有两套测试?
哦,Test和AllTests都被跑了一遍,无伤大雅。
再写个AllTests测试套件,作为对default中的全部controllers的测试,文件放在tests/application/default/controllers文件夹(与IndexControllerTest.php在一起)
AllTests.php
<?php
/**
* Ebuyhotel
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
*
* @category Ebuyhotel
* @package UnitTests
* @copyright Copyright (c) 2008-2008 lxw (matchless.liu@gmail.com)
* @version $Id: AllTests.php 26 2008-06-20 16:09:24Z lxw $
*/
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'Default_Controllers_AllTests::main');
}
/**
* Test helper
*/
require_once dirname(dirname(dirname(dirname(__FILE__)))) . '/TestHelper.php';
require_once dirname(__FILE__).'/IndexControllerTest.php';
class Default_Controllers_AllTests extends PHPUnit_Framework_TestSuite
{
public static function main()
{
$result = PHPUnit_TextUI_TestRunner::run(self::suite());
return $result;
}
public function __construct()
{
$this->setName('Default_Controllers_AllTests');
$this->addTestSuite('IndexController_AllTests');
}
public static function suite()
{
return new self();
}
}
if (PHPUnit_MAIN_METHOD == 'Default_Controllers_AllTests::main') {
Default_Controllers_AllTests::main();
}
|
以PHP Script方式运行,结果如下图:
以PHPUnit Test方式运行,结果如下图:
其它的逐级AllTests可以仿此构建,这个留待以后具体构建时再说。
阅读(2597) | 评论(0) | 转发(0) |