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

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

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

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

面向?qū)ο蟮木幊讨载S富多彩,部分是由于對象間的相互聯(lián)系與作用。一個單一的對象就能封裝一個復(fù)雜的子系統(tǒng),使那些很復(fù)雜的操作能夠通過一些方法的調(diào)用而簡化。(無所不在的數(shù)據(jù)庫連接就是這樣的一個對象實例。)
然而經(jīng)常有這樣的情況,對象間的交互性是如此復(fù)雜以至于我們不得不面對類似“先有雞還是先有蛋”這樣傷腦筋的問題:如何創(chuàng)建并測試這樣一個對象,他要么依賴于很多已創(chuàng)建的對象,要么依賴于其他一些難以意識到的情況,如整個數(shù)據(jù)庫的創(chuàng)建和測試。

問題

如何分隔并測試一個與其他對象和資源有關(guān)的代碼段?又如何再創(chuàng)建一個或多個對象、程序來驗證你的代碼能正常運(yùn)行?

解決方案

當(dāng)用situ(或在一個仿真的程序環(huán)境中)測試一個對象代價不菲或困難重重時,就可用偽對象來模擬這個行為。偽對象有同真實對象一樣的接口,但卻能提供預(yù)編譯響應(yīng),能跟蹤方法調(diào)用,并驗證調(diào)用次序。
偽對象是測試的“特別力量”。他們被秘密訓(xùn)練,滲透進(jìn)目標(biāo)代碼,模擬并監(jiān)視通信方式,回報結(jié)果。偽對象有助于查找和消除程序漏洞并能支持更多正常調(diào)試環(huán)境下的“防危險”操作。


注:The ServerStub

偽對象模式是另一種測試模式ServerStub的擴(kuò)展。ServerStub模式替代一個資源并返回其方法所調(diào)用的相應(yīng)值。當(dāng)其參與指定次序的方法的調(diào)用時ServerStub就成了偽對象。

其并非是一個設(shè)計模式

本章與其他章不同,因為偽對象是一個測試模式而不是設(shè)計模式。這類似于一個附加的章節(jié),但對它的使用 確實很值得你納入到編碼進(jìn)程中。另一個不同是我們不再關(guān)注這個模式如何編碼之類的基礎(chǔ)問題,而是強(qiáng)調(diào) 如何在SimpleTest中使用偽對象。

本章先舉一個非常簡單的例子來示范SimpleTest下偽對象的基本機(jī)制。然后向你演示如何使用偽對象幫助重構(gòu)已有代碼與如何測試新的解決方案。

樣本代碼

偽對象是對象在測試中的一個替代品,用它測試代碼更加簡便。例如,替代一個真實的數(shù)據(jù)連接——這個真實的數(shù)據(jù)連接由于一些原因而不能實際連接——你就可以創(chuàng)建一個偽對象來模擬。這意味著偽對象需要準(zhǔn)確地回應(yīng)代碼中所調(diào)用的相同的應(yīng)用程序接口。

讓我們創(chuàng)建一個偽對象來替代一個簡單的名為Accumulator的類,這是一個求和的類。如下是最初的Accumulator類:

// PHP4
class Accumulator {
var $total=0;
function add($item) {
$this->total = $item;
}
function total() {
return $this->total;
}
}

這個類中add()函數(shù)先累加值到$total變量中,再交由total()函數(shù)返回 。 一個簡單的累加也可以如下面這樣(下面的代碼被編寫為一個函數(shù),但它也可以寫成一個類)。

function calc_total($items, &$sum) {
foreach($items as $item) {
$sum->add($item);
}
}
function calc_tax(&$amount, $rate=0.07) {
return round($amount->total() * $rate,2);
}

第一個函數(shù)calc_total()用一個累加的動作求一系列值的和。下面是簡單的測試:

class MockObjectTestCase extends UnitTestCase {
function testCalcTotal() {
$sum =& new Accumulator;
calc_total(array(1,2,3), $sum);
$this->assertEqual(6, $sum->total());
}
}


讓我們關(guān)注第二個例子。假設(shè)實現(xiàn)一個真實的累加動作的代價很大。那么用一個簡單的對象來替代它并回應(yīng)相關(guān)代碼就是很好的做法了。使用SimpleTest,你可以用如下代碼創(chuàng)建一個偽累加動作:

Mock::generate(‘Accumulator’);
class MockObjectTestCase extends UnitTestCase {
// ...
function testCalcTax() {
$amount =& new MockAccumulator($this);
$amount->setReturnValue(‘total’,200);
$this->assertEqual(
14, calc_tax($amount));
}
}

為了使用偽對象,具有代表性的做法是你親自寫一個新類(并不要求馬上做)。幸運(yùn)的是,SimpleTest有一種容易的手段來實現(xiàn) Mock::generate() 方法。

在上面的例子中,這種手段創(chuàng)建了一個名為MockAccumulator的類來響應(yīng)所有Accumulator類的方法。另外,偽累加的動作還有其他手段來操作偽對象自身的實例。例如 setReturnValue()。給出一個方法名和一個值,

setReturnValue()就可以改變偽對象而給出對應(yīng)方法所調(diào)用的值。因此,這條語句$amount->setReturnValue(‘total’, 200)返回200而不論何時調(diào)用了total()方法。

一旦進(jìn)行完初始化工作后,你可以傳遞MockAccumulator類到calc_tax()函數(shù)來演示一個在真實的Accumulator對象空間中的動作。

如果你止步于此——即用一個對象來返回所調(diào)用函數(shù)的“封裝”響應(yīng)——你只是使用了ServerStub模式。 用偽對象來驗證方法的調(diào)用不限于此,因為它可以不限次序與次數(shù)。

下面是一個通過對象來驗證“數(shù)據(jù)流”的例子:

class MockObjectTestCase extends UnitTestCase {
// ...
function testCalcTax() {
$amount =& new MockAccumulator($this);
$amount->setReturnValue(‘total’,200);
$amount->expectOnce(‘total’);
$this->assertEqual(
14, calc_tax($amount));
$amount->tally();
}
}

這里expectOnce()方法使用了一個字符串,它包含你想調(diào)用的方法名 。而tally()實際上用來檢查你的想法是否實現(xiàn)。這里,如果MockAccumulator::total()只調(diào)用一次或不調(diào)用,測試將失敗。

在很多情況下你可以使用偽對象的”跟蹤”特性。例如,如果你傳遞一個具有三個值的數(shù)組到calc_total(),Accumulator::add()是否也如你所想的調(diào)用了三次呢?

class MockObjectTestCase extends UnitTestCase {
// ...
function testCalcTotalAgain() {
$sum =& new MockAccumulator($this);
$sum->expectOnce(‘add’);
calc_total(array(1,2,3), $sum);
$sum->tally();
}
}

那,這里發(fā)生了什么?傳遞調(diào)用的測試失敗。SimpleTest的錯誤消息如下所示:

MockObject PHP4 Unit Test
1) Expected call count for [add] was [1] got [3] at line [51]
in testcalctotalagain in mockobjecttestcase
FAILURES!!!
Test cases run: 1/1, Passes: 2, Failures: 1, Exceptions: 0

錯誤消息指出了盡管add() 方法被調(diào)用三次,但expectOnce()卻一次也沒用到。取代expectOnce()的可行方法是使用expectCallCount()。

class MockObjectTestCase extends UnitTestCase {
// ...
function testCalcTotalAgain() {
$sum =& new MockAccumulator($this);
$sum->expectCallCount(‘add’, 3);
calc_total(array(1,2,3), $sum);
$sum->tally();
}
}

偽對象扮演了一個演員的角色——這個角色由SeverStub提供合理的測試數(shù)據(jù)來響應(yīng)方法的調(diào)用——并且作為一個評判的角色,驗證所調(diào)用的方法是否符合預(yù)想。

重構(gòu)已有程序

下面讓我們用偽對象來幫助重構(gòu)一個已有程序。考慮一個簡單的腳本,它可以模擬你在無數(shù)的PHP程序中所期望的行為:例如一個當(dāng)檢查到你未登錄時要求登錄的頁面;與此類似的還有表單處理頁面;它能在成功登錄后顯示不同內(nèi)容并提供登出的功能。 讓我們寫一個這樣的頁面。首先,對還未登錄的用戶顯示一個登錄表單。

<html>
<body>
<form method=”post”>
Name:<input type=”text” name=”name”> Password:<input type=”password” name=”passwd”>
<input type=”submit” value=”Login”>
</form>
</body>
</html>

接著,顯示登錄成功后的內(nèi)容:


<html>
<body>Welcome <?php echo $_SESSION[‘name’]; ?>
<br>Super secret member only content here.
<a href=”<?php echo SELF; ?>?clear”>Logout</a>
</body>
</html>

加入表單處理的功能,session(會話)開始,還有登出的功能,整體看起來應(yīng)該類似這樣:

session_start();
define(‘SELF’,
‘http://’.$_SERVER[‘SERVER_NAME’].$_SERVER[‘PHP_SELF’]);
if (array_key_exists(‘name’, $_REQUEST)
&& array_key_exists(‘passwd’, $_REQUEST)
&& ‘admin’ == $_REQUEST[‘name’]
&& ‘secret’ == $_REQUEST[‘passwd’]) {
$_SESSION[‘name’] = ‘admin’;
header(‘Location: ‘.SELF);
}
if (array_key_exists(‘clear’, $_REQUEST)) {
unset($_SESSION[‘name’]);
}
if (array_key_exists(‘name’, $_SESSION)
&& $_SESSION[‘name’]) { ?>
<html>
<body>Welcome <?=$_SESSION[‘name’]?>
<br>Super secret member only content here.
<a href=”<?php echo SELF; ?>?clear”>Logout</a>
</body>
</html> <?php
} else { ?>
<html>
<body>
<form method=”post”>
Name:<input type=”text” name=”name”> Password:<input type=”password” name=”passwd”>
<input type=”submit” value=”Login”>
</form>
</body>
</html> <?php
}

重構(gòu)這個程序的一個目的應(yīng)該是使其成為一個“易于測試”的程序�;谶@個目的,如果你還選擇一些PHP中的方便特性——如超級全局變量——你將失去測試上的簡潔性。

例如,如果你直接就用了$_SESSION,即意味著只有一種途徑可以測試這個代碼,就是改變$_SESSION。如果你忘了將$_SESSION改回先前已知的狀態(tài),各種測試間就會互相干擾。

一個好的解決方法是封裝$_SESSION到另一個類中,傳遞所封裝類的實例到任何想要訪問$_SESSION的對象。如果你創(chuàng)建了一個已封裝對象的偽對象用于測試,你能夠完全控制對象對所調(diào)用方法的響應(yīng)(就像ServerStub那樣)并且你能核實它是如何調(diào)用的(那正是創(chuàng)建偽對象的目的)。

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

共4頁上一頁1234下一頁
來源:模板無憂//所屬分類:PHP教程/更新時間:2008-08-22
相關(guān)PHP教程