Yii框架特点及测试考虑
1. 簡介
Yii 是一個(gè)基于部件、用于開發(fā)大型 Web 應(yīng)用的高性能 PHP 框架。它將 Web 編程中的可重用性發(fā)揮到極致,能夠顯著加速開發(fā)進(jìn)程。Yii(讀作“易”)代表簡單(easy)、高效(efficient)、可擴(kuò)展 (extensible)。它是輕量級的,又裝配了很好很強(qiáng)大的緩存部件,因此尤其適合開發(fā)大流量的應(yīng)用,比如門戶、論壇、內(nèi)容管理系統(tǒng)(CMS)、電子商務(wù)系統(tǒng),等等。
Yii 是一個(gè)純OOP的通用Web編程框架,和大多數(shù) PHP 框架一樣,Yii 是一個(gè) MVC 框架。
Yii在設(shè)計(jì)時(shí)借鑒和集成了很多其他著名web編程框架和應(yīng)用的思想和工作:
● Prado:這是Yii的思想的主要來源。Yii采用了它的基于部件和事件驅(qū)動的編程范式,數(shù)據(jù)庫抽象層,模塊應(yīng)用框架,國際化和本地化以及其它一些東西。
● Ruby on Rails:Yii繼承了它的易于配置的特點(diǎn)。Yii還參考了它的活動記錄設(shè)計(jì)模式的實(shí)現(xiàn)。
● jQuery:作為JavaScript框架的基礎(chǔ)集成到Y(jié)ii中
● Symfony:Yii參考了它的過濾器設(shè)計(jì)以及插件框架
● Joomla:Yii參考了它的模塊設(shè)計(jì)以及消息傳遞體系。
2. YII的設(shè)計(jì)模式
下面將以一個(gè)樹圖描述了一個(gè)簡單的web服務(wù)所產(chǎn)生的目錄結(jié)構(gòu)。通過這個(gè)目錄結(jié)構(gòu),我們會發(fā)現(xiàn)除了Web常見的資源、圖片、CSS、主題等元素外,還有Yii所特有的部件、控制器、模塊、消息、視圖等元素。下面我們將介紹Yii特有的元素的功能及實(shí)現(xiàn)。
testdrive/
index.php Web 應(yīng)用入口腳本文件
assets/ 包含公開的資源文件
css/ 包含 CSS 文件
images/ 包含圖片文件
themes/ 包含應(yīng)用主題
protected/ 包含受保護(hù)的應(yīng)用文件
yiic yiic 命令行腳本
yiic.bat Windows 下的 yiic 命令行腳本
commands/ 包含自定義的 'yiic' 命令
shell/ 包含自定義的 'yiic shell' 命令
components/ 包含可重用的用戶部件
MainMenu.php 'MainMenu' 掛件類
Identity/php 用來認(rèn)證的 'Identity' 類
views/ 包含掛件的視圖文件
mainMenu.php 'MainMenu' 掛件的視圖文件
config/ 包含配置文件
console.php 控制臺應(yīng)用配置
main.php Web 應(yīng)用配置
controllers/ 包含控制器的類文件
SiteController.php 默認(rèn)控制器的類文件
extensions/ 包含第三方擴(kuò)展
messages/ 包含翻譯過的消息
models/ 包含模型的類文件
LoginForm.php 'login' 動作的表單模型
ContactForm.php 'contact' 動作的表單模型
runtime/ 包含臨時(shí)生成的文件
views/ 包含控制器的視圖和布局文件
layouts/ 包含布局視圖文件
main.php 所有視圖的默認(rèn)布局
site/ 包含 'site' 控制器的視圖文件
contact.php 'contact' 動作的視圖
index.php 'index' 動作的視圖
login.php 'login' 動作的視圖
system/ 包含系統(tǒng)視圖文件
2.1. YII的MVC模式
Yii 實(shí)現(xiàn)了 Web 編程中廣為采用的“模型-視圖-控制器”(MVC)設(shè)計(jì)模式。MVC 致力于分離業(yè)務(wù)邏輯和用戶界面,這樣開發(fā)者可以很容易地修改某個(gè)部分而不影響其它。在 MVC 中,模型表現(xiàn)信息(數(shù)據(jù))和業(yè)務(wù)規(guī)則;視圖包含用戶界面中用到的元素,比如文本、表單輸入框;控制器管理模型和視圖間的交互。
除了 MVC,Yii 還引入了一個(gè)叫做 application 的前端控制器,它表現(xiàn)整個(gè)請求過程的運(yùn)行環(huán)境。Application 接收用戶的請求并把它分發(fā)到合適的控制器作進(jìn)一步處理。
下圖描述了一個(gè) Yii 應(yīng)用的靜態(tài)結(jié)構(gòu):
圖 1 Yii 應(yīng)用的靜態(tài)結(jié)構(gòu)
下圖描述了一個(gè) Yii 應(yīng)用處理用戶請求時(shí)的典型流程:
圖 2 Yii 應(yīng)用的典型流程
1. 用戶訪問 http://www.example.com/index.php?r=post/show&id=1,Web 服務(wù)器執(zhí)行入口腳本 index.php 來處理該請求。
2. 入口腳本建立一個(gè)應(yīng)用實(shí)例并運(yùn)行之。
3. 應(yīng)用從一個(gè)叫 request 的應(yīng)用部件獲得詳細(xì)的用戶請求信息。
4. 通過 urlManager 這個(gè)應(yīng)用部件,確定用戶要請求的控制器和動作。
5. 應(yīng)用建立一個(gè)被請求的控制器實(shí)例來進(jìn)一步處理用戶請求,控制器確定由它的actionShow 方法來處理 show 動作。然后它建立并應(yīng)用和該動作相關(guān)的過濾器,如果過濾器允許的話,動作被執(zhí)行。
6. 動作從數(shù)據(jù)庫讀取一個(gè) ID 為 1 的 Post 模型。
7. 動作使用 Post 模型來渲染一個(gè)叫 show 的視圖。
8. 視圖讀取 Post 模型的屬性并顯示之。
9. 視圖運(yùn)行一些掛件。
10. 視圖的渲染結(jié)果嵌在布局中。
11. 動作結(jié)束視圖渲染并顯示結(jié)果給用戶。
2.1.1. 調(diào)試模式
一個(gè) Yii 應(yīng)用能夠根據(jù) YII_DEBUG 常量的指示以調(diào)試模式或者生產(chǎn)模式運(yùn)行。默認(rèn)情況下該常量定義為 false,代表生產(chǎn)模式。要以調(diào)試模式運(yùn)行,在包含 yii.php 文件前將此常量定義為 true。應(yīng)用以調(diào)試模式運(yùn)行時(shí)效率較低,因?yàn)樗鼤稍S多內(nèi)部日志。從另一個(gè)角度來看,發(fā)生錯(cuò)誤時(shí)調(diào)試模式會產(chǎn)生更多的調(diào)試信息,因而在開發(fā)階段非常有用。但在正式上線之后,則需要去掉調(diào)試模式,因?yàn)檎{(diào)試模式會打印很多額外信息,這些信息會在一定程度上影響其運(yùn)行的性能。
2.2. 應(yīng)用
應(yīng)用表示一個(gè)請求處理的上下文。它的主要任務(wù)是分解用戶的請求并且把它分發(fā)到恰當(dāng)?shù)目刂破髦羞M(jìn)行進(jìn)一步的處理。它也保存應(yīng)用級的配置,因此也被稱為前端控制器。
默認(rèn)情況下,應(yīng)用是 CWebApplication 類的一個(gè)實(shí)例。 要對其進(jìn)行定制, 通常是在應(yīng)用實(shí)例被創(chuàng)建的時(shí)候提供一個(gè)配置文件 (或數(shù)組) 來初始化其屬性值。 另一個(gè)定制應(yīng)用的方法就是擴(kuò)展 CWebApplication 類。配置是一個(gè)鍵值對的數(shù)組。 每個(gè)鍵名都對應(yīng)應(yīng)用實(shí)例的一個(gè)屬性, 相應(yīng)的值為屬性的初始值。 如果應(yīng)用的配置非常復(fù)雜,也可以將其分解成多個(gè)文件,每個(gè)文件返回配置數(shù)組的一部分。
應(yīng)用根目錄表示包含所有安全敏感的PHP腳本和數(shù)據(jù)的根目錄。缺省情況下,它是包含入口腳本的目錄的名為protected的子目錄。應(yīng)當(dāng)組織Web用戶訪問這個(gè)目錄。
可以通過靈活的部件框架方便的進(jìn)行應(yīng)用功能的定制和擴(kuò)展。應(yīng)用管理著部件的集合,每個(gè)部件實(shí)現(xiàn)特定的功能。例如,應(yīng)用可能在CUrlManager 和 CHttpRequest的幫助下處理一個(gè)用戶的請求。
Yii預(yù)定義了一個(gè)核心部件集合來提供Web應(yīng)用中的常用功能,下面是CWebApplication類中預(yù)定義 核心部件:
assetManager:CAssetManager - 管理私有資源文件的發(fā)布
authManager:CAuthManager – 管理基于角色的訪問控制(RBAC)
cache:CCache – 提供數(shù)據(jù)緩存功能
clientScript:CClientScript – 管理客戶端腳本(javascript和CSS)
coreMessages:CPhpMessageSource – 提供Yii框架所使用的轉(zhuǎn)換過的核心消息
db:CDbConnection – 提供數(shù)據(jù)庫連接
errorHandler:CErrorHandler – 處理未被捕獲的PHP錯(cuò)誤和異常
messages:CPhpMessageSource – 提供Yii應(yīng)用使用的轉(zhuǎn)換過的消息
request:CHttpRequest – 提供和用戶請求相關(guān)的信息
securityManager:CSecurityManager – 提供安全相關(guān)的服務(wù),如散列,加密
session:CHttpSession – 提供會話相關(guān)的功能
statePersister:CStatePersister – 提供全局持續(xù)狀態(tài)方法
urlManager:CUrlManager – 提供URL解析和創(chuàng)建功能
user:CWebUser – 表示當(dāng)前用戶的身份信息
themeManager:CThemeManager – 管理主題
處理一個(gè)用戶請求時(shí),一個(gè)應(yīng)用將會經(jīng)歷這樣一個(gè)生命周期:
1. 設(shè)置自動加載和錯(cuò)誤處理類
2. 注冊核心應(yīng)用部件
3. 加載應(yīng)用配置
4. 使用CApplication::init()初始化應(yīng)用
加載靜態(tài)應(yīng)用部件
5. 觸發(fā)onBeginRequest事件
6. 處理用戶請求:
解析用戶請求
創(chuàng)建控制器
運(yùn)行控制器
7. 觸發(fā)onEndRequest事件
2.3. 控制器
控制器是 CController 或者其子類的實(shí)例。 用戶請求應(yīng)用時(shí),創(chuàng)建控制器。 控制器執(zhí)行請求action,action通常引入必要的模型并提供恰當(dāng)?shù)囊晥D。 最簡單的action僅僅是一個(gè)控制器類方法,此方法的名字以action開始。
控制器有默認(rèn)的action。用戶請求沒指定哪一個(gè)action執(zhí)行時(shí),將執(zhí)行默認(rèn)的action。 缺省情況下,默認(rèn)的action名為index。可以通過設(shè)置CController::defaultAction改變默認(rèn)的action。
下邊是最小的控制器。因?yàn)榭刂破魑炊x任何action,請求時(shí)會拋出異常。
class SiteController extends CController
{
}
CWebApplication在處理一個(gè)新請求時(shí),實(shí)例化一個(gè)控制器。程序通過控制器的ID,并按一定規(guī)則確定控制器類及控制器類所在位置。
一個(gè)動作可以定義為一個(gè)函數(shù)或者一個(gè)動作類。當(dāng)請求這個(gè)動作時(shí),控制器實(shí)例化這個(gè)類。這樣就可以復(fù)用和重用動作。
過濾器是配置為控制器動作之前或之后執(zhí)行的一段代碼。例如可以設(shè)計(jì)一個(gè)性能過濾器用于計(jì)時(shí)動作執(zhí)行的時(shí)間。一個(gè)動作可以有多個(gè)過濾器。過濾器可以定義為控制器類的方法,也可以是CFilter類的子類。
2.4. 模型
模型是 CModel 或其子類的實(shí)例。 模型用于保持?jǐn)?shù)據(jù)以及和數(shù)據(jù)相關(guān)的業(yè)務(wù)規(guī)則。模型描述了一個(gè)單獨(dú)的數(shù)據(jù)對象。它可以是數(shù)據(jù)表中的一行數(shù)據(jù)或者用戶輸入的一個(gè)表單。數(shù)據(jù)中的各個(gè)字段都描述了模型的一個(gè)屬性。這些屬性都有一個(gè)標(biāo)簽,都可以被一套可靠的規(guī)則驗(yàn)證。
Yii 從表單模型和 active record 實(shí)現(xiàn)了兩種模型。 它們都繼承自基類 CModel。
表單模型是CFormModel的實(shí)例。表單模型用于保存通過收集用戶輸入得來的數(shù)據(jù)。這樣的數(shù)據(jù)通常被收集,使用,然后被拋棄。例如,在一個(gè)登錄頁面上,我們可以使用一個(gè)表單模型來描述諸如用戶名,密碼這樣的由最終用戶提供的信息。
Active Record (AR) 是一種面向?qū)ο箫L(fēng)格的,用于抽象數(shù)據(jù)庫訪問的設(shè)計(jì)模式。任何一個(gè) AR 對象都是 CActiveRecord 或其子類的實(shí)例, 它描述的數(shù)據(jù)表中的單獨(dú)一行數(shù)據(jù)。這行數(shù)據(jù)中的字段被描述成 AR 對象的一個(gè)屬性。
2.5. 視圖
視圖是一個(gè)包含了主要的用戶交互元素的PHP腳本。他可以包含PHP語句,但是建議這些語句不要去改變數(shù)據(jù)模型,且最好能夠保持其單純性(單純作為視圖)!為了實(shí)現(xiàn)邏輯和界面分離,大部分的邏輯應(yīng)該被放置于控制器或模型里,而不是視圖里。
視圖有一個(gè)當(dāng)其被渲染(render)時(shí)用于校驗(yàn)的名稱。視圖的名稱與其腳本名稱是一樣的。例如:視圖 edit 的名稱出自一個(gè)名為 edit.php 的腳本文件。通過 CController::render() 調(diào)用視圖的名稱可以渲染一個(gè)視圖。這個(gè)方法將在 protected/views/ControllerID 目錄下尋找對應(yīng)的視圖文件。
在視圖腳本內(nèi)部,可以通過 $this 來訪問控制器實(shí)例。可以在視圖里以 $this->propertyName 的方式 pull 控制器的任何屬性。也可以用以下 push 的方式傳遞數(shù)據(jù)到視圖里:
$this->render('edit', array(
'var1'=>$value1,
'var2'=>$value2,
));
在以上的方式中, render() 方法將提取數(shù)組的兩個(gè)參數(shù)到變量里。其產(chǎn)生的結(jié)果是,在視圖腳本里,我們可以直接訪問變量 $var1 和 $var2。
布局是一種特殊的視圖文件用來修飾視圖。它通常包含了用戶交互過程中常用到的一部分視圖。
組件是 CWidget 或其子類的實(shí)例。它是一個(gè)主要用于描述特定意圖的組成部分。組件通常內(nèi)嵌于一個(gè)視圖來產(chǎn)生一些復(fù)雜卻獨(dú)立的用戶界面。例如,一個(gè)日歷組件可以用于渲染一個(gè)復(fù)雜的日歷界面。組件可以在用戶界面上更好的實(shí)現(xiàn)重用。
系統(tǒng)視圖的渲染通常用于展示 Yii 的錯(cuò)誤和日志信息。例如,當(dāng)用戶請求來一個(gè)不存在的控制器或動作時(shí),Yii 會拋出一個(gè)異常來解釋這個(gè)錯(cuò)誤。 這時(shí),Yii 就會使用一個(gè)特殊的系統(tǒng)視圖來展示這個(gè)錯(cuò)誤。
2.6. 部件
Yii 應(yīng)用構(gòu)建于對象是規(guī)范編寫的部件之上。部件是 CComponent 或其衍生類的實(shí)例。使用部件主要就是涉及訪問其屬性和掛起/處理它的事件。基類 CComponent 指定了如何定義屬性和事件。
部件的屬性就像對象的公開成員變量,可以被讀取或設(shè)置部件屬性。
部件事件是一種特殊的屬性,它可以將方法(稱之為事件句柄(event handlers))作為它的值。綁定(分配)一個(gè)方法到一個(gè)事件將會導(dǎo)致方法在事件被掛起處自動被調(diào)用。因此部件行為可能會被一種在部件開發(fā)過程中不可預(yù)見的方式修改。部件事件以 on 開頭的命名方式定義。
部件可以綁定一個(gè)或者多個(gè)行為。一個(gè)行為(behavior) 就是一個(gè)對象,其方法可以被它綁定的部件通過收集功能的方式來實(shí)現(xiàn) '繼承(inherited)',而不是專有化繼承(即普通的類繼承)。簡單的來說,就是一個(gè)部件可以以'多重繼承'的方式實(shí)現(xiàn)多個(gè)行為的綁定。
2.7. 開發(fā)流程
用yii開發(fā)一個(gè)web程序的基本流程,如下所示:
1. 創(chuàng)建目錄結(jié)構(gòu)
2. 配置 application,即修改application配置文件
3. 每種類型的數(shù)據(jù)都創(chuàng)建一個(gè) model 類來管理
4. 每種類型的用戶請求都創(chuàng)建一個(gè) controller 類。 依據(jù)實(shí)際的需求對用戶請求進(jìn)行分類。一般來說,如果一個(gè)model類需要用戶訪問,就應(yīng)該對應(yīng)一個(gè)controller類。
5. 實(shí)現(xiàn) actions 和相應(yīng)的 views。這是真正需要我們編寫的工作。
6. 在controller類里配置需要的action filters 。
7. 如果需要主題功能,編寫 themes。
8. 如果需要 internationalization國際化功能,編寫翻譯語句。
9. 使用 caching 技術(shù)緩存數(shù)據(jù)和頁面。
10. 最后調(diào)整好程序和發(fā)布。
3. 測試考慮
Yii提供了自動化測試的方法,包括單元測試和功能測試,其中單元測試是驗(yàn)證一個(gè)單元的代碼能夠像預(yù)想的一樣工作,對于Yii來說,就是驗(yàn)證類中的每個(gè)方法都可以正確的工作,輸入不同的參數(shù)和數(shù)據(jù),來驗(yàn)證類中每個(gè)方法能夠輸出符合預(yù)期的數(shù)據(jù)和行為。
功能測試是確定一個(gè)功能、特征(例如博客系統(tǒng)中的發(fā)表管理)可以像預(yù)想的一樣工作。由于一個(gè)功能可能包含多個(gè)類,因此相比較單元測試,功能測試在更高的級別。
Yii的測試框架是建立在PHPUnit之上的。
3.1. 定義Fixtures
一套自動化的case往往會被執(zhí)行多次。為了保證這個(gè)測試的過程是可重復(fù)的,我們需要在執(zhí)行case的時(shí)候,讓其初始狀態(tài)是處于一個(gè)已知確定的狀態(tài)。這個(gè)狀態(tài),我們叫做fixture,通俗的講,就是在測試之前所需要的環(huán)境的所有初始狀態(tài)。
建立一個(gè)數(shù)據(jù)庫的fixture在web應(yīng)用開發(fā)過程中可能是一個(gè)最耗時(shí)的部分。Yii框架引入了一個(gè)叫做CDbFixtureManager的應(yīng)用組件來緩和這個(gè)問題,大體來說,在執(zhí)行一個(gè)測試集合時(shí)它做了這樣幾件事情:
在所有case運(yùn)行前,它把與本次運(yùn)行case相關(guān)的所有數(shù)據(jù)表置于一個(gè)已知的狀態(tài)。在一個(gè)單一的case運(yùn)行前,它把一些特定的表復(fù)位到一個(gè)已知的狀態(tài)。
在執(zhí)行一個(gè)方法的過程中,它提供了對與這些fixture有關(guān)的數(shù)據(jù)的訪問。
為了使用CDbFixtureManager這個(gè)類,一般會進(jìn)行如下配置:
return array(
'components'=>array(
'fixture'=>array(
'class'=>'system.test.CDbFixtureManager',
),
),
);
對于這些我們想提供作為fixture的數(shù)據(jù),一般會將其放在/protected/tests/fixtures目錄下。這些數(shù)據(jù)文件按照php的形式組織在一起,統(tǒng)稱為fixture file。每個(gè)fixture file會返回一個(gè)數(shù)組,該數(shù)組包含一些特定的表的某些行的預(yù)設(shè)值。并且文件名跟表名保持一致。
3.2. 單元測試
我們可以總結(jié)出如下在Yii中書寫單元測試的原則:
● 單元測試是通過實(shí)現(xiàn)繼承自CTestCase或CDbTestCase類的XyzTest類來實(shí)現(xiàn),其中Xyz表示要測試的類名。CTestCase用于通用單元測試而CDbTestCase用于活動記錄模型類的測試。由于PHPUnit_Framework_TestCase是這兩個(gè)類的父類,因此我們可以使用繼承自此類的所有方法。
● 單元測試類以文件XyzTest.php的形式保存。為了方便起見,一般單元測試的case會存儲在protected/tests/unit下。
● 測試類主要是一個(gè)待測試的類的方法的集合,如果這個(gè)待測試的類叫做Abc,那么這個(gè)測試類一般會起名為testAbc。
● 一個(gè)測試類經(jīng)常包含一系列的斷言,(例如assertTrue, assertEquals),作為驗(yàn)證目標(biāo)類行為的檢驗(yàn)點(diǎn)。
以如何為active record模型類建立單測為例,我們來看看究竟如何寫一個(gè)單測case。
假設(shè)我們想測試一個(gè)blog的評論模型類,首先要?jiǎng)?chuàng)建一個(gè)CommonTest.php并保存在/protected/tests/unit/CommentTest.php,代碼如下:
class CommentTest extends CDbTestCase
{
public $fixtures=array(
'posts'=>'Post',
'comments'=>'Comment',
);
......?
}
在上述類中,我們制定了fixture的成員變量是一個(gè)數(shù)組,該數(shù)組將會用戶接下來的測試case中。
Fixture names允許我們在測試方法中以一種非常方便的方式來訪問fixture data。最典型的用法如下:
$comments = $this->comments;
接下來,我們就可以書寫textApprove方法來測試評論視圖類中的approve 方法了。
3.3. 功能測試
● 像單元測試一樣,功能測試時(shí)通過實(shí)現(xiàn)繼承自CWebTestCase類的XyzTest類來實(shí)現(xiàn),其中Xyz表示要測試的類名。由于 PHPUnit_Extensions_SeleniumTestCase是CwebTestCase的父類,因此可以采用繼承自此類的所有方法。
● 功能測試類以文件XyzTest.php的形式保存。
● 測試類主要包含命名為testABC的測試方法的集合,其中Abc經(jīng)常是要測試的功能的名字,例如testLogin
● 一個(gè)測試方法經(jīng)常包含一系列的指令來發(fā)出命令以與被測試Web應(yīng)用交互。它也包含一些斷言狀態(tài)來驗(yàn)證Web應(yīng)用如預(yù)想一樣響應(yīng)。
3.4. 其他
3.4.1基于module的單元測試方法
有的yii版本不支持基于phpUnit 的單元的測試,那么我們也可以有其他的辦法來做單元測試。具體的方法就是把test作為一個(gè)module。目錄部署結(jié)構(gòu)為:
webRoot/protected/modules/test/controller/ABC.php
在上述ABC.php里,我們可以創(chuàng)建繼承自業(yè)務(wù)的類,并在這些類中構(gòu)建對應(yīng)的action,每個(gè)action都可以調(diào)用需要測試的函數(shù)。通過在瀏覽器上直接請求這些action,并打印出相關(guān)信息,即可實(shí)現(xiàn)對上述這些函數(shù)的測試。如想測試的action函數(shù)為actionAdd。
根據(jù)yii的url解析規(guī)則,上述Add方法的調(diào)用即為該url的請求http://*.*.*.*/index.php?r=test/ABC/Add 。 如果適當(dāng)?shù)募由戏祷亟Y(jié)果的展現(xiàn),那么就能很明確的知道該函數(shù)的返回值與預(yù)期的是否相符。
3.4.2Firebug輔助測試
Firebug也是當(dāng)今web開發(fā)程序員的一個(gè)利器,同時(shí)也可以作為測試人員的一個(gè)參考。Firebug會記錄各個(gè)請求的參數(shù),post數(shù)據(jù),響應(yīng)數(shù)據(jù)。當(dāng)功能出現(xiàn)問題時(shí),測試人員可以根據(jù)事先設(shè)計(jì)的參數(shù)和預(yù)期的返回的數(shù)據(jù)來判定是view傳遞的參數(shù)錯(cuò)誤,還是php根據(jù)邏輯所計(jì)算出的返回?cái)?shù)據(jù)值不對。從而來定位錯(cuò)誤的真正位置。
(全文完)
作者:mimical
本文轉(zhuǎn)自百度技術(shù)51CTO博客,原文鏈接:http://blog.51cto.com/baidutech/743559,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的Yii框架特点及测试考虑的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 根据生日获取年龄
- 下一篇: ASP.NET Button控件的Use