Chinaunix首页 | 论坛 | 博客
  • 博客访问: 480342
  • 博文数量: 95
  • 博客积分: 2117
  • 博客等级: 大尉
  • 技术积分: 2301
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-16 21:10
个人简介

辽宁铁岭人,现居大连。1970年生。 先后供职于 中国国际海运网、大连学堂科技、大连华仁视线网络科技有限公司、大连中科海云科技有限公司,任职技术总监。 精通PHP、JAVA、Javascript、HTML、CSS等网络编程技术及Linux操作系统。 精通面向对象编程、设计模式、重构及互联网产品设计。

文章分类

全部博文(95)

文章存档

2013年(31)

2012年(2)

2011年(34)

2010年(25)

2008年(3)

分类:

2008-07-23 22:30:02

下面我将尽可能如实记录实践这个项目的每一个步骤,因为有些步骤在一般情况下是可选的,但在本次实践中可能会因为省略了这些步骤引起前后不一致。

一、修改入口文件:
Zend Framework的单一入口就是index.php文件,默认的文件很简练紧凑,不需要做大幅修改,但我还是对它进行了一点改动。
为了在后续的所有文件中都能有一个相对固定的引用文件的起点,以免在不同的文件中使用相对路径引用文件时迷路,我指定了一个常量,用来指向整个项目的根文件夹,这个常量被命名为ROOT_PATH。后面所有使用相对路径的地方都改成以此为参照的绝对路径引用。
为了使整个程序易于移植,这个常量的定义使用了如下方式:

define ('ROOT_PATH', dirname(dirname(__FILE__)));


并且在index.php指定了输出的字符集:

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) |
给主人留下些什么吧!~~