日韩天天综合网_野战两个奶头被亲到高潮_亚洲日韩欧美精品综合_av女人天堂污污污_视频一区**字幕无弹窗_国产亚洲欧美小视频_国内性爱精品在线免费视频_国产一级电影在线播放_日韩欧美内地福利_亚洲一二三不卡片区

《PHP設(shè)計(jì)模式介紹》第六章 偽對(duì)象模式(3)_PHP教程

編輯Tag賺U幣
教程Tag:暫無Tag,歡迎添加,賺取U幣!

推薦:《PHP設(shè)計(jì)模式介紹》第五章 注冊(cè)模式
我們通常認(rèn)為避免使用全局變量是一種好的選擇,因此,對(duì)象經(jīng)常被作為參數(shù)從一段代碼傳遞到另一段。但是傳遞實(shí)例的一個(gè)問題就是對(duì)象有時(shí)候不知道將要傳遞給誰——?經(jīng)過一個(gè)函數(shù)后才被傳

這個(gè)“bootstrap”文件運(yùn)行新程序時(shí)應(yīng)如下所示:


<?php
require_once ‘classes.inc.php’;
define(‘SELF’, ‘http://www.example.com/path/to/page.php’);
$page =& new PageDirector(new Session, new Response);
$page->run();
?>

該文件包含了所需的已定義類,并為自己定義了一個(gè)常量,給PageDirector類(其用于傳遞類Session 和類Response所依賴的實(shí)例來組成構(gòu)造函數(shù))創(chuàng)建了一個(gè)實(shí)例來執(zhí)行PageDirector::run()方法。

現(xiàn)在讓我們來創(chuàng)建一些測(cè)試的實(shí)例來詳細(xì)說明重構(gòu)后的運(yùn)用程序應(yīng)該有的功能。

require_once ‘simpletest/unit_tester.php’;
require_once ‘simpletest/reporter.php’; require_once ‘simpletest/mock_objects.php’; require_once ‘simpletest/web_tester.php’;
require_once ‘classes.inc.php’; Session::init();
class PageWebTestCase extends WebTestCase { /*...*/ } class ResponseTestCase extends UnitTestCase { /*...*/ } class UserLoginTestCase extends UnitTestCase { /*...*/ } class SessionTestCase extends UnitTestCase { /*...*/ }
class PageDirectorTestCase extends UnitTestCase { /*...*/ }
$test = new GroupTest(‘Application PHP4 Unit Test’);
$test->addTestCase(new PageWebTestCase);
$test->addTestCase(new ResponseTestCase);
$test->addTestCase(new UserLoginTestCase);
$test->addTestCase(new SessionTestCase);
$test->addTestCase(new PageDirectorTestCase);

這段代碼或多或少的展示了一個(gè)典型的運(yùn)用程序的測(cè)試文件該是何種模樣。它一開始就包含了一些SimpleTest文件,也包括了用偽對(duì)象來測(cè)試的mock_object.php文件。接著,那些輔助類被包含進(jìn)來,方法Session::init()被調(diào)用,seesion開始。

緊接著的全是以“安全無害”為目標(biāo)而開始的測(cè)試實(shí)例,類WebTestCase確保所有程序按要求執(zhí)行, 然后是單獨(dú)的用于新設(shè)計(jì)的類的測(cè)試(盡管這種類本章不會(huì)詳述)。最后是我們接下去會(huì)討論的PageDirectorTestCase類。

類PageDirector的核心任務(wù)是協(xié)調(diào)類Session和類Response的對(duì)象,產(chǎn)生最終的網(wǎng)頁輸出結(jié)果。

Mock::Generate(‘Session’);
Mock::Generate(‘Response’);
define(‘SELF’, ‘testvalue’);
class PageDirectorTestCase extends UnitTestCase {
// ...
}

在這段代碼的一開始,Mock::generate()創(chuàng)建了偽對(duì)象類的定義并定義了一個(gè)后面將要用到的常量。

假設(shè)對(duì)類Session 和類 Response的測(cè)試已經(jīng)存在,下一步就是創(chuàng)建偽Session來模擬類 Session的狀態(tài)。這個(gè)偽對(duì)象的設(shè)置和我們一開始所演示的例子極其類似。

因?yàn)镻ageDirector::run()方法正回顯內(nèi)容,你可以用輸出緩存內(nèi)容的辦法來捕獲它,看看是否正確。


class PageDirectorTestCase extends UnitTestCase {
// ...
function TestLoggedOutContent() {
$session =& new MockSession($this);
$session->setReturnValue(‘get’, null, array(‘user_name’));
$session->expectOnce(‘get’, array(‘user_name’));
$page =& new PageDirector($session, new Response);
ob_start();
$page->run();
$result = ob_get_clean();
$this->assertNoUnwantedPattern(‘/secret.*content/i’, $result);
$this->assertWantedPattern(‘/<form.*<input[^>]*text[^>]*’
.’name.*<input[^>]*password[^>]*passwd/ims’
,$result);
$session->tally();
}
}

這段代碼證明了在SimpleTest中使用偽對(duì)象的必要性。我們來看看其中創(chuàng)建偽對(duì)象的一行代碼$session =&new MockSession($this)。你可以使用繼承自SimpleStub類(參見http://simpletest.sf.net/SimpleTest/MockObjects/SimpleStub.html#sec-methodsummary)的方法來創(chuàng)建你所希望的從對(duì)象(如同你在測(cè)試代碼時(shí)所做的那樣)返回的結(jié)果.下一步,實(shí)例化PageDirector類并用MockSession代替正式使用時(shí)的類來實(shí)例化相關(guān)代碼。

注:setReturnValue()方法

setReturnValue()方法通過指定當(dāng)偽對(duì)象的特定方法被調(diào)用時(shí)返回何值來讓偽對(duì)象以一個(gè)“替身”的身份融入代碼。已經(jīng)有了一些這種方法的變體:比如指定以一定次序返回一系列值的做法,還有以參數(shù)代替值來返回結(jié)果的做法。

expectOnce()方法

expectOnce()方法通過建立一些假想,這些假想是關(guān)于什么時(shí)候方法被調(diào)用以及多久調(diào)用一次,來允許你的偽對(duì)象以“批評(píng)者”的角色來測(cè)試代碼。這些假想當(dāng)你在測(cè)試中調(diào)用偽對(duì)象的tally()方法時(shí)會(huì)被報(bào)告。

class PageDirector {
var $session;
var $response;
function PageDirector(&$session, &$response) {
$this->session =& $session;
$this->response =& $response;
}
}

因?yàn)镻ageDirector類認(rèn)為自己不是處于一個(gè)測(cè)試環(huán)境而是處于一個(gè)真實(shí)正常的運(yùn)用程序環(huán)境中,它回顯結(jié)果到瀏覽器。既然你實(shí)際上在測(cè)試時(shí)并不希望這個(gè)動(dòng)作,你就可以通過PHP輸出緩存的特性(參見http://php.net/outcontrol)來捕獲執(zhí)行時(shí)它往瀏覽器發(fā)送了什么。


class PageDirector {
// ...
function run() {
if (!$this->isLoggedIn()) {
$this->showLogin();
}
this->response->display();
}
function isLoggedIn() {
return ($this->session->get(‘user_name’)) ? true : false;
}
function showLogin() {
$this->response->addBody(‘<form method=”post”>’);
$this->response->addBody(‘Name:<input type=”text” name=”name”>’);
$this->response->addBody(“\n”);
$this->response->addBody(
‘Password:<input type=”password” name=”passwd”>’);
$this->response->addBody(“\n”);
$this->response->addBody(‘<input type=”submit” value=”Login”>’);
$this->response->addBody(‘</form>’);
}
}
如同這段程序代碼一樣,測(cè)試代碼本身也可以進(jìn)行重構(gòu)。在本例中,你可以看到緩存輸出的訣竅是其將被多次復(fù)用,因此使用“析構(gòu)法”重構(gòu)可以使測(cè)試本身簡(jiǎn)化。(重新調(diào)用的那些以“test”為開頭的方法是隨整個(gè)測(cè)試一起自動(dòng)運(yùn)行的;你也可以自己創(chuàng)建一些使測(cè)試更簡(jiǎn)潔的方法。)

下面的代碼段演示了緩存輸出被重構(gòu)為runPage方法的結(jié)果,它給人的感覺就像是當(dāng)用戶登錄時(shí)另一個(gè)對(duì)輸出的測(cè)試。


class PageDirectorTestCase extends UnitTestCase {
// ...
function TestLoggedOutContent() {
$session =& new MockSession($this);
$session->setReturnValue(‘get’, null, array(‘user_name’));
$session->expectOnce(‘get’, array(‘user_name’));
$page =& new PageDirector($session, new Response);
$result = $this->runPage($page);
$this->assertNoUnwantedPattern(‘/secret.*content/i’, $result);
$this->assertWantedPattern(‘/<form.*<input[^>]*text[^>]*’
.’name.*<input[^>]*password[^>]*passwd/ims’
,$result);
$session->tally();
}
function TestLoggedInContent() {
$session =& new MockSession($this);
$session->setReturnValue(‘get’, ‘admin’, array(‘user_name’));
$session->expectAtLeastOnce(‘get’);
$page =& new PageDirector($session, new Response);
$result = $this->runPage($page);
$this->assertWantedPattern(‘/secret.*content/i’, $result);
$this->assertNoUnwantedPattern(‘/<form.*<input[^>]*text[^>]*’
.’name.*<input[^>]*password[^>]*passwd/ims’
,$result);
$session->tally();
}
function runPage(&$page) {
ob_start();
$page->run();
return ob_get_clean();
}
}

接下來,將加入一個(gè)檢查條件到PageDirector::run()方法來看看用戶是否已經(jīng)登錄并決定顯示什么模板:

class PageDirector {
// ...
function run() {
if ($this->isLoggedIn()) {
$this->showPage(
new UserLogin($this->session->get(‘user_name’)));
} else {
$this->showLogin();
}
$this->response->display();
}
function showPage(&$user) {
$vars = array(
‘name’ => $user->name()
,’self’ => SELF
);
$this->response->addBodyTemplate(‘page.tpl’, $vars);
}
}

page.tpl看上去可能像這樣:

Welcome <?php echo $name; ?>
<br>Super secret member only content here.
<a href=”<?php echo $self; ?>?clear”>Logout</a>


此時(shí),MockSession扮演了ServerStub的角色來控制決定用戶是否登錄的條件。它的功能也類似評(píng)判者,決定這個(gè)信息是否通過如下兩個(gè)途徑被正確的使用:一個(gè)是明確地被預(yù)先定義并通過tally()被驗(yàn)證,另一個(gè)是不直接的生成正確的輸出,而是通過ServerStub返回的值來生成。

為了繼續(xù)重構(gòu)這段代碼,下一步要跳到前面的進(jìn)程。將要做兩個(gè)動(dòng)作:清除已經(jīng)登錄的用戶和驗(yàn)證登錄頁面提交的用戶名和密碼是否存在。

分享:《PHP設(shè)計(jì)模式介紹》第四章 單件模式
幾乎所有面向?qū)ο蟮某绦蛑校傆幸粌蓚(gè)資源被創(chuàng)建出來,在程序應(yīng)用中持續(xù)被共享使用。例如,這樣的一個(gè)資源,在一個(gè)電子商務(wù)程序的數(shù)據(jù)庫連接中使用:這個(gè)連接在應(yīng)用程序啟動(dòng)時(shí)初始化,程序于是

來源:模板無憂//所屬分類:PHP教程/更新時(shí)間:2008-08-22
相關(guān)PHP教程