重構(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) && ‘a(chǎn)dmin’ == $_REQUEST[‘name’] && ‘secret’ == $_REQUEST[‘passwd’]) { $_SESSION[‘name’] = ‘a(chǎn)dmin’; 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)建偽對象的目的)。
具備了這個思想,讓我們看看如何封裝$_SESSION之類的全局變量。
class Session { function Session() { $this->init(); } function init() { if (!isset($_SESSION)) { if (headers_sent()) { trigger_error( ‘Session not started before creating session object’); } else { session_start(); } } } function isValid($key) { return array_key_exists($key, $_SESSION); } function get($key) { return (array_key_exists($key, $_SESSION)) ? $_SESSION[$key] : null; } function set($key, $value) { $_SESSION[$key] = $value; } function clear($key) { unset($_SESSION[$key]); } }
類Session封裝了全局變量$_SESSION。對類SESSION的測試非常類似于對前期的已注冊的類的改良測試(參見第5章),但是卻無任何通過參數(shù)獲得或設(shè)置相應(yīng)值的意圖。
你也許注意到了構(gòu)造函數(shù)調(diào)用了Session::init()方法。為什么這個方法不是構(gòu)造函數(shù)的一部分呢?這樣分開的好處是你能靜態(tài)調(diào)用它并確保session已經(jīng)開始。下面是一個如何使用該類的例子。
Session::init(); $page =& new PageDirector(new Session);
大部分測試方面的文獻很推崇偽對象并建議你親自寫一個。如果你打算那樣做,開始測試時你就只需要充實那些你需要的方法就可以了。譬如,一個用于處理代碼的ServerStub的Session類很可能是這樣的:
class MyMockSessionUser1 { function isValid($key) { return (‘user_id’ == $key) ? true : false; } function get($key) { if (‘user_id’ == $key) { return 1; } } }
幸運的是,你可以用SimpleTest來避免那些易范的錯誤。Mock::generate()方法允許你創(chuàng)建一個類來實例化或動態(tài)地配置你想要的結(jié)果。
注:偽對象技術(shù) SimpleTest所使用的方法僅是偽對象的多種用法之一。偽對象的代碼傳遞是另一種。隨著PHP5的到來,你也許能看到偽對象以對象中的__call()方法來執(zhí)行。
以下是如何用SimpleTest生成的偽對象來測試并重構(gòu)MyMockSessionUser1類(如上例中)。
Mock::Generate(‘Session’); class PageDirectorTestCase extends UnitTestCase { function testSomethingWhichUsesSession() { $session =& new MockSession($this); $session->setReturnValue(‘isValid’, true); $session->setReturnValue(‘get’, 1); // ... } }
出處:phpchina
責(zé)任編輯:bluehearts
上一頁 php設(shè)計模式介紹之偽對象模式 [2] 下一頁 php設(shè)計模式介紹之偽對象模式 [4]
◎進入論壇網(wǎng)絡(luò)編程版塊參加討論
|