復(fù)旦大學高級web技術(shù)課件09云計算之GAE_第1頁
復(fù)旦大學高級web技術(shù)課件09云計算之GAE_第2頁
復(fù)旦大學高級web技術(shù)課件09云計算之GAE_第3頁
復(fù)旦大學高級web技術(shù)課件09云計算之GAE_第4頁
復(fù)旦大學高級web技術(shù)課件09云計算之GAE_第5頁
已閱讀5頁,還剩41頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、云計算之GAE技術(shù)內(nèi)容GAE概述GAE應(yīng)用的限制數(shù)據(jù)持久化技術(shù)數(shù)據(jù)庫訪問:JDOQL和GQL應(yīng)用層技術(shù) JavaGAE服務(wù)GAE單元測試學習資料:/intl/zh-CN/appengine/articles/GAE架構(gòu)GAE概述Google App Engine 可讓開發(fā)者在 Google 的基礎(chǔ)架構(gòu)上運行您的網(wǎng)絡(luò)應(yīng)用程序。App Engine 應(yīng)用程序易于構(gòu)建和維護,并可根據(jù)運行者的訪問量和數(shù)據(jù)存儲需要的增長輕松擴展。使用 Google App Engine,將不再需要維護服務(wù)器:運行者只需上傳應(yīng)用程序,它便可立即為用戶提供服務(wù)。Google App Engine 支持以幾種編程語言編寫的應(yīng)

2、用程序。Python和Java在 App Engine 中,運行者只需為使用的資源付費。可以免費開始使用 App Engine。所有應(yīng)用程序都可以使用多達 500 MB 的存儲空間,以及可支持每月約 500 萬頁面瀏覽量的足夠 CPU 和帶寬,完全免費。GAE特性動態(tài)網(wǎng)絡(luò)服務(wù),提供對常用網(wǎng)絡(luò)技術(shù)的完全支持持久存儲空間,支持查詢、分類和事務(wù)自動擴展和負載平衡用于對用戶進行身份驗證和使用 Google 帳戶發(fā)送電子郵件的 API一種功能完整的本地開發(fā)環(huán)境,可以在開發(fā)者計算機上模擬 Google App Engine用于在指定時間和定期觸發(fā)事件的計劃任務(wù)GAE應(yīng)用的限制帶寬和CPU配額限制請求大小

3、10 兆字節(jié) 響應(yīng)大小 10 兆字節(jié) 請求持續(xù)時間 30 秒 同時動態(tài)請求 30 * 應(yīng)用程序文件的最大數(shù)目 1,000 靜態(tài)文件的最大數(shù)目 1,000 應(yīng)用程序文件的最大規(guī)模 10 兆字節(jié) 靜態(tài)文件的最大大小 10 兆字節(jié) 所有應(yīng)用程序和靜態(tài)文件的最大總大小 150 兆字節(jié)GAE數(shù)據(jù)持久化技術(shù)App Engine 提供了一個強大的分布式數(shù)據(jù)存儲服務(wù),其中包含查詢引擎和事務(wù)功能。就像分布式網(wǎng)絡(luò)服務(wù)器隨訪問量增加一樣,該分布式數(shù)據(jù)存儲區(qū)也會隨數(shù)據(jù)而增加。該 App Engine 數(shù)據(jù)存儲區(qū)與傳統(tǒng)關(guān)系數(shù)據(jù)庫不同。數(shù)據(jù)對象(或“實體”)有一類和一組屬性。查詢可以檢索按屬性值過濾和分類的指定種類的實體

4、。屬性值可以是受支持的屬性值類型中的任何一種。數(shù)據(jù)存儲區(qū)實體是“無架構(gòu)”的。數(shù)據(jù)實體的結(jié)構(gòu)由應(yīng)用程序代碼提供和執(zhí)行。Java JDO/JPA 接口和 Python 數(shù)據(jù)存儲區(qū)接口包括用于在您的應(yīng)用程序內(nèi)應(yīng)用和執(zhí)行結(jié)構(gòu)的功能。您的應(yīng)用程序還可以直接訪問數(shù)據(jù)存儲區(qū)以根據(jù)需要應(yīng)用或多或少的結(jié)構(gòu)。數(shù)據(jù)存儲區(qū)高度一致并使用樂觀并發(fā)控制。如果有其他進程嘗試更新某實體,而同時該實體位于以固定次數(shù)進行重新嘗試的事務(wù)中,此時該實體將更新。應(yīng)用程序可以在一個事務(wù)中執(zhí)行多項數(shù)據(jù)存儲區(qū)操作(全部成功或者全部失敗,從而確保數(shù)據(jù)的完整性)。數(shù)據(jù)存儲區(qū)通過其分布式網(wǎng)絡(luò)使用“實體組”實現(xiàn)事務(wù)。一個事務(wù)操作一個組內(nèi)的實體。同一

5、組的實體存儲在一起,以高效執(zhí)行事務(wù)。應(yīng)用程序可以在實體創(chuàng)建時將實體分配到組。數(shù)據(jù)存儲區(qū)App Engine 數(shù)據(jù)存儲區(qū)存儲數(shù)據(jù)對象(稱為“實體”)并對其執(zhí)行查詢。一個實體具有一個或多個屬性(若干受支持數(shù)據(jù)類型中某一類型的命名值)。屬性可以是對另一實體的引用。數(shù)據(jù)存儲區(qū)可以在一個事務(wù)中執(zhí)行多個操作,如果任一操作失敗則回滾整個事務(wù)。這對于分布式網(wǎng)絡(luò)應(yīng)用程序尤其有用,在這種分布式網(wǎng)絡(luò)應(yīng)用中,多個用戶可以同時訪問或處理同一數(shù)據(jù)對象。與傳統(tǒng)數(shù)據(jù)庫不同,該數(shù)據(jù)存儲區(qū)使用分布式體系結(jié)構(gòu)管理向超大型數(shù)據(jù)集的擴展。App Engine 應(yīng)用程序可以通過描述數(shù)據(jù)對象之間的關(guān)系,以及定義查詢的索引,來優(yōu)化數(shù)據(jù)的分布

6、方式。App Engine 數(shù)據(jù)存儲區(qū)具有高度的一致性,但不是關(guān)系數(shù)據(jù)庫。雖然該數(shù)據(jù)存儲區(qū)接口有許多與傳統(tǒng)數(shù)據(jù)庫相同的功能,但也具有獨特的特征,它采用了不同的數(shù)據(jù)設(shè)計和管理方式,可以充分利用自動擴展功能。實體和屬性App Engine 數(shù)據(jù)存儲區(qū)中的數(shù)據(jù)對象稱為實體。一個實體具有一個或多個屬性(若干數(shù)據(jù)類型中某一類型的命名值),包括整數(shù)值、浮點值、字符串、日期、二進制數(shù)據(jù)等。每個實體還有一個唯一標識該實體的鍵。最簡單的鍵具有數(shù)據(jù)存儲區(qū)提供的類型和唯一的數(shù)字 ID。ID 還可以是應(yīng)用程序提供的字符串。應(yīng)用程序可以使用實體的鍵或執(zhí)行與實體屬性匹配的查詢,從數(shù)據(jù)存儲區(qū)中抓取實體。查詢可以返回零個或多

7、個實體,并可以返回按屬性值排序的結(jié)果。查詢還可以限制數(shù)據(jù)存儲區(qū)返回的結(jié)果的數(shù)量,以節(jié)省內(nèi)存和運行時間。與關(guān)系數(shù)據(jù)庫不同,App Engine 數(shù)據(jù)存儲區(qū)不要求指定類型的所有實體要有相同的屬性。應(yīng)用程序可指定并強制其數(shù)據(jù)模型使用 SDK 附帶的庫或其自己的代碼。一個屬性可具有一個或多個值。具有多個值的屬性可具有混合類型的值。對具有多個值的屬性進行查詢可測試是否有任何值滿足查詢條件。這樣可以使這些屬性能夠用于測試成員身份。查詢和索引App Engine 數(shù)據(jù)存儲區(qū)查詢對某一指定類型(數(shù)據(jù)類)的每個實體進行操作。它對實體屬性值和鍵指定零個或多個過濾條件,以及零個或多個排序順序。如果一個實體對于查詢的

8、過濾條件和排序順序中所提及的每個屬性都具有至少一個值(可能為 null),且屬性值滿足所有過濾條件,那么將返回該實體作為查詢的結(jié)果。每個數(shù)據(jù)存儲區(qū)查詢都使用一個索引,即包含按指定順序排列的查詢結(jié)果的表格。App Engine 應(yīng)用程序會在一個配置文件中定義其索引。開發(fā)網(wǎng)絡(luò)服務(wù)器在遇到未配置索引的查詢時會自動為該文件添加建議。您可以在上傳該應(yīng)用程序之前編輯該文件,以手動調(diào)整索引。當應(yīng)用程序?qū)?shù)據(jù)存儲區(qū)實體做出更改時,數(shù)據(jù)存儲區(qū)會使用正確的結(jié)果更新索引。當應(yīng)用程序執(zhí)行查詢時,數(shù)據(jù)存儲區(qū)會直接從相應(yīng)的索引中抓取結(jié)果。該機制可支持許多查詢,且適用于大部分應(yīng)用程序。然而,該機制不支持您可能慣用的其他數(shù)據(jù)

9、庫技術(shù)中的一些查詢類型。事務(wù)和實體組在 App Engine 數(shù)據(jù)存儲區(qū)中,所有創(chuàng)建、更新或刪除實體的嘗試都可以在一個事務(wù)中進行。事務(wù)可確保對實體所做的所有更改都保存到數(shù)據(jù)存儲區(qū)中,或者,在失敗的情況下不做任何更改。這樣便可確保實體中數(shù)據(jù)的一致性。您可以使用事務(wù) API 在單一事務(wù)中對一個實體執(zhí)行多個操作。例如,假設(shè)您要使對象中的計數(shù)器域遞增。為此,您需要讀取計數(shù)器的值,計算新的值,然后存儲值。如果沒有事務(wù),那么在您讀取值和更新值之間,可能有另一進程使計數(shù)器遞增,這會導致應(yīng)用程序覆蓋已更新的值。在單一事務(wù)中進行讀取、計算和寫入操作可確保沒有其他進程干擾遞增。您可以在單一事務(wù)中對多個實體進行更改

10、。為了支持這種做法,App Engine 需要預(yù)先了解哪些實體將一起更新,從而使用支持事務(wù)的方式來存儲這些實體。您在創(chuàng)建實體時,必須聲明這一實體與另一實體同屬一個實體組。在一個事務(wù)中抓取、創(chuàng)建、更新或刪除的所有實體都必須位于同一實體組中。實體組是由實體之間關(guān)系的層次結(jié)構(gòu)定義的。要在組中創(chuàng)建實體,您應(yīng)聲明該實體是組中現(xiàn)有的另一實體的子實體。另一實體為父實體。不通過父實體創(chuàng)建的實體是根實體。如果一個根實體沒有任何子實體,則其所在的實體組中只有這一個實體。每個實體都有一條從根實體到其自身的父實體-子實體關(guān)系路徑(最短的路徑?jīng)]有父實體)。該路徑是實體完整鍵中必不可少的一部分。完整的鍵可以用路徑中各實體

11、的類型以及 ID 或鍵名來表示。數(shù)據(jù)存儲區(qū)使用開放式并發(fā)來管理事務(wù)。在一個應(yīng)用程序?qū)嵗龑⒏膽?yīng)用到實體組中的實體時,對于該組中任何實體的所有其他更新嘗試都會立即失敗。應(yīng)用程序可再次嘗試事務(wù),將其應(yīng)用到更新的數(shù)據(jù)。配額和限制對于數(shù)據(jù)存儲區(qū) API 的每次調(diào)用都會計算在數(shù)據(jù)存儲區(qū) API 調(diào)用配額內(nèi)。請注意,有些庫的調(diào)用會導致對基礎(chǔ)數(shù)據(jù)存儲區(qū) API 的多次調(diào)用。由應(yīng)用程序發(fā)送到數(shù)據(jù)存儲區(qū)的數(shù)據(jù)會計算在數(shù)據(jù)發(fā)送到(數(shù)據(jù)存儲區(qū))API 配額內(nèi)。應(yīng)用程序從數(shù)據(jù)存儲區(qū)接收的數(shù)據(jù)都會計算在數(shù)據(jù)接收自(數(shù)據(jù)存儲區(qū))API 配額內(nèi)。應(yīng)用程序當前存儲在數(shù)據(jù)存儲區(qū)中的數(shù)據(jù)總量不得超過存儲的數(shù)據(jù)(可調(diào)整)配額。這包

12、括實體屬性和鍵,但不包括索引。數(shù)據(jù)存儲區(qū)操作消耗的 CPU 時間不得超過以下配額:CPU 時間(可調(diào)整) 數(shù)據(jù)存儲區(qū) CPU 時間 使用JDO和JDOQLPersistenceManager pm = PMF.get().getPersistenceManager(); String query = select * from + Employee.class.getName() + where lastName = Smith;List employees = (List) pm.newQuery(query).execute();設(shè)置 JDO要使用 JDO 訪問數(shù)據(jù)存儲區(qū),App Engi

13、ne 應(yīng)用程序需進行以下設(shè)置:JDO 和 DataNucleus App Engine 插件 JAR 必須位于應(yīng)用程序的 war/WEB-INF/lib/ 目錄。命名為 jdoconfig.xml 的配置文件必須位于應(yīng)用程序的 war/WEB-INF/classes/META-INF/ 目錄中,配置為使 JDO 使用 App Engine 數(shù)據(jù)存儲區(qū)。項目的構(gòu)建過程必須對編譯的數(shù)據(jù)類執(zhí)行后編譯“增強”步驟以使其與 JDO 實現(xiàn)相關(guān)聯(lián)。如果使用的是 Eclipse Google 插件,則以上三項已為處理。預(yù)先準備的類EmployeePrimaryKey Persistent(valueStrat

14、egy = IdGeneratorStrategy.IDENTITY) private Long id; Persistent private String firstName; Persistent private String lastName; Persistent private Date hireDate; 創(chuàng)建數(shù)據(jù) PersistenceManager pm = PMF.get().getPersistenceManager(); Employee e = new Employee(Alfred, Smith, new Date(); try pm.makePersistent(e

15、); finally pm.close(); 鍵每個實體都具有一個在 App Engine 的所有實體中唯一的鍵。一個完整的鍵包含若干條信息,其中包括應(yīng)用程序 ID、類型和實體 ID。對象的鍵存儲在實例的某一個字段中。開發(fā)者可以使用 PrimaryKey 批注來標識主鍵字段。應(yīng)用程序可在創(chuàng)建對象時以字符串形式提供鍵的 ID 部分,也可以允許數(shù)據(jù)存儲區(qū)自動生成數(shù)字 ID。完整的鍵在數(shù)據(jù)存儲區(qū)的所有實體中必須是唯一的。換句話說,在類型相同且具有相同父實體組(如果有)的所有對象中,一個對象必須具有唯一的 ID。您可以使用字段類型和批注來選擇所需的鍵的行為。通過鍵獲取對象Key k = KeyFact

16、ory.createKey(Employee.class.getSimpleName(), Alfred.Smith);Employee e = pm.getObjectById(Employee.class, k);更新對象使用 JDO 更新對象的一種方式是抓取對象,然后在返回該對象的 PersistenceManager 仍然處于打開狀態(tài)的情況下對該對象進行修改。當關(guān)閉 PersistenceManager 時,會保留修改。public void updateEmployeeTitle(User user, String newTitle) PersistenceManager pm =

17、PMF.get().getPersistenceManager(); try Employee e = pm.getObjectById(Employee.class, user.getEmail(); if (titleChangeIsAuthorized(e, newTitle) e.setTitle(newTitle); else throw new UnauthorizedTitleChangeException(e, newTitle); finally pm.close(); 刪除對象要將對象從數(shù)據(jù)存儲區(qū)中刪除,請對該對象調(diào)用 PersistenceManager 的 delete

18、Persistent() 方法。pm.deletePersistent(e);如果某個對象的字段同樣包含持久的子對象,則這些子對象也將被刪除。查詢和索引Query query = pm.newQuery(Employee.class); query.setFilter(lastName = lastNameParam); query.setOrdering(hireDate desc); query.declareParameters(String lastNameParam);try List results = (List) query.execute(Smith); if (result

19、s.iterator().hasNext() for (Employee e : results) / . else / . no results . finally query.closeAll(); 字符串組裝查詢(SQL注入?) Query query = pm.newQuery(select from Employee + where lastName = lastNameParam + order by hireDate desc + parameters String lastNameParam) List results = (List) query.execute(Smith)

20、;混合型Query query = pm.newQuery(Employee.class, lastName = lastNameParam order by hireDate desc); query.declareParameters(String lastNameParam); List results = (List) query.execute(Smith);引入索引App Engine 數(shù)據(jù)存儲區(qū)會為應(yīng)用程序要進行的每個查詢都保留一個索引。當應(yīng)用程序?qū)?shù)據(jù)存儲區(qū)實體做出更改時,數(shù)據(jù)存儲區(qū)會使用正確的結(jié)果更新索引。當應(yīng)用程序執(zhí)行查詢時,數(shù)據(jù)存儲區(qū)會直接從相應(yīng)的索引中抓取結(jié)果。應(yīng)用程序

21、對查詢中使用的每個類型、過濾器屬性和操作符以及排序順序的組合都具有一個索引。Text 和 Blob 值未編入索引,所以不能通過查詢查找。數(shù)據(jù)存儲區(qū)按照以下步驟執(zhí)行查詢數(shù)據(jù)存儲區(qū)會標識符合查詢的種類、過濾器屬性、過濾器操作符和排序順序的索引。數(shù)據(jù)存儲區(qū)會使用該查詢的過濾器值在滿足全部過濾器條件的第一個實體處開始掃描該索引。數(shù)據(jù)存儲區(qū)繼續(xù)掃描索引,同時返回每個實體,直到發(fā)現(xiàn)不滿足過濾條件的下一個實體,直到達到索引末尾,或者直到已收集了查詢所請求的最多結(jié)果。事務(wù)事務(wù)是一項或一系列數(shù)據(jù)存儲區(qū)操作,這些操作要么全部成功,要么全部失敗。如果事務(wù)成功完成,則會對數(shù)據(jù)存儲區(qū)產(chǎn)生所有預(yù)期的作用。如果事務(wù)失敗,則

22、不會起任何作用。每個數(shù)據(jù)存儲區(qū)寫入操作都是原子操作。要么試圖創(chuàng)建、更新或刪除實體,要么不執(zhí)行。如果有太多用戶試圖同時修改一個實體,那么這種高占用率將可能引發(fā)操作失敗。當應(yīng)用程序達到配額限制時,也可能會引發(fā)操作失敗。數(shù)據(jù)存儲區(qū)內(nèi)部錯誤也是引發(fā)操作失敗的原因。在上述所有情況下,操作將不起作用,且數(shù)據(jù)存儲區(qū) API 將引發(fā)異常。JDO事務(wù)的一個案例import javax.jdo.Transaction;import ClubMembers; / not shown/ . / PersistenceManager pm = .; Transaction tx = pm.currentTransact

23、ion(); try tx.begin(); ClubMembers members = pm.getObjectById(ClubMembers.class, k12345); members.incrementCounterBy(1); pm.makePersistent(members); mit(); finally if (tx.isActive() tx.rollback(); 使用JPAJava 持久性 API (JPA) 是一個用于將包含數(shù)據(jù)的對象存儲在關(guān)系數(shù)據(jù)庫中的標準接口。該標準定義用于對 Java 對象進行批注、通過查詢檢索對象,并使用事務(wù)與數(shù)據(jù)庫交互的接口。使用 JPA

24、 接口的應(yīng)用程序可以在不使用任何供應(yīng)商特定的數(shù)據(jù)庫代碼的情況下使用不同的數(shù)據(jù)庫。JPA 使您的應(yīng)用程序可輕松地在不同的數(shù)據(jù)庫供應(yīng)商之間移植。GQL語法SELECT * FROM WHERE AND . ORDER BY ASC | DESC , ASC | DESC . LIMIT , OFFSET := | | = | = | != := IN := ANCESTOR IS GQL要點與使用 SQL 一樣,GQL 關(guān)鍵字不區(qū)分大小寫。類型和屬性名稱區(qū)分大小寫。每個 GQL 查詢始終以 SELECT * FROM 開頭可選 WHERE 子句對結(jié)果集進行過濾以得出符合一個或多個條件的實體。IN

25、運算符將屬性的值與列表中的每一項進行比較IN 和 != 運算符在后臺使用多個查詢可選的 LIMIT 子句使查詢在前 count 個實體后停止返回結(jié)果。LIMIT 子句最大為 1000。SQL與GQL的區(qū)別Google App Engine的Datastore使用一個與SQL類似的語言,叫做“GQL”。在GQL中,SELECT語句僅可以用于一個表。因為要跨越不只一臺機器, GQL不支持效率很低的JOIN語句。欲創(chuàng)建一對多和多對多的關(guān)系,可使用ReferenceProperty()。采用這種無共享的方式,即使磁盤壞了,系統(tǒng)也不致癱瘓。在GQL中,SELECT語句中的WHERE從句只容許對僅僅一列進

26、行、=、或5 AND level 20ORDER BY level ASC, score DESCJava 服務(wù) APIMemcache網(wǎng)址抓取郵件圖像Google 帳戶Memcache對于某些任務(wù),高性能的可擴展網(wǎng)絡(luò)應(yīng)用程序通常在穩(wěn)定持久存儲之前使用分布式內(nèi)存數(shù)據(jù)緩存,或用分布式內(nèi)存數(shù)據(jù)緩存來代替穩(wěn)定持久存儲。App Engine 提供了此用途的內(nèi)存緩存服務(wù)。網(wǎng)址抓取App Engine 應(yīng)用程序可以抓取資源,并通過互聯(lián)網(wǎng)使用 HTTP 和 HTTPS 請求與其他主機通信。應(yīng)用程序使用網(wǎng)址抓取服務(wù)來進行請求。郵件App Engine 應(yīng)用程序可以代表應(yīng)用程序管理員和擁有 Google 帳戶的

27、用戶發(fā)送電子郵件。應(yīng)用程序使用郵件服務(wù)來發(fā)送電子郵件。圖像App Engine 提供了使用專用圖像服務(wù)來操作圖像數(shù)據(jù)的功能。圖像服務(wù)可以調(diào)整圖像大小,旋轉(zhuǎn)、翻轉(zhuǎn)和裁剪圖像。它還能夠使用預(yù)先定義的算法提高照片質(zhì)量。Google 帳戶App Engine 應(yīng)用程序可以使用 Google 帳戶驗證用戶。應(yīng)用程序可以檢測到當前用戶是否以 Google 帳戶登錄,并且可以將用戶重定向到 Google 帳戶登錄頁面,以便登錄或新建一個帳戶。在用戶登錄到應(yīng)用程序時,應(yīng)用程序可以訪問用戶的電子郵件地址。應(yīng)用程序也可以檢測當前用戶是否為管理員,這樣便可在應(yīng)用程序中輕松實現(xiàn)僅管理員區(qū)域。使用本地服務(wù)實現(xiàn)進行單元測

28、試這里將描述如何使用 JUnit 3 完成此任務(wù)。建立執(zhí)行環(huán)境創(chuàng)建基礎(chǔ) TestCase編寫數(shù)據(jù)存儲區(qū)測試建立執(zhí)行環(huán)境您首先需要做的是確保您的單元測試的類路徑上存在 appengine-api-stubs.jar 和 appengine-local-runtime.jar(這些 jar 作為 SDK 的一部分發(fā)行)。接下來,您需要創(chuàng)建一個 ApiProxy.Environment 實例并使用 ApiProxy 注冊該實例。當您的應(yīng)用程序在本地運行時,容器將使用 appengine-web.xml 配置文件中的內(nèi)容為您創(chuàng)建該實例,但在本例中,我們的容器是 JUnit,且 JUnit 對 App

29、Engine 或 appengine-web.xml 一無所知。因此,應(yīng)由測試負責確保 ApiProxy.Environment 已正確構(gòu)造并注冊。建立執(zhí)行環(huán)境(續(xù))import com.google.apphosting.api.ApiProxy;class TestEnvironment implements ApiProxy.Environment public String getAppId() return Unit Tests; public String getVersionId() return 1.0; public void setDefaultNamespace(Stri

30、ng s) public String getRequestNamespace() return null; public String getDefaultNamespace() return null; public String getAuthDomain() return null; public boolean isLoggedIn() return false; public String getEmail() return null; public boolean isAdmin() return false; / .ApiProxy.setEnvironmentForCurre

31、ntThread(new TestEnvironment();創(chuàng)建基礎(chǔ) TestCaseimport com.google.appengine.tools.development.ApiProxyLocalImpl;import com.google.apphosting.api.ApiProxy;public class LocalServiceTestCase extends TestCase Override public void setUp() throws Exception super.setUp(); ApiProxy.setEnvironmentForCurrentThrea

32、d(new TestEnvironment(); ApiProxy.setDelegate(new ApiProxyLocalImpl(new File(.); Override public void tearDown() throws Exception / not strictly necessary to null these out but theres no harm either ApiProxy.setDelegate(null); ApiProxy.setEnvironmentForCurrentThread(null); super.tearDown(); 測試錯誤發(fā)生時電

33、子郵件是否正常發(fā)送的示例import com.google.appengine.api.mail.dev.LocalMailService;import com.google.appengine.tools.development.ApiProxyLocalImpl;public class BugNotificationTest extends TestCase public void testEmailGetsSent() ApiProxyLocalImpl proxy = (ApiProxyLocalImpl) ApiProxy.getDelegate(); LocalMailServi

34、ce mailService = (LocalMailService) proxy.getService(mail); mailService.clearSentMessages(); Bug b = new Bug(); b.setSeverity(Severity.LOW); b.setText(NullPointerException when trying to update phone number.); b.setOwner(max); new BugDAO().createBug(b); assertEquals(1, mailService.getSentMessages().

35、size(); / . tests the content and recipient of the email 編寫數(shù)據(jù)存儲區(qū)測試默認情況下,數(shù)據(jù)存儲區(qū)服務(wù)的本地實現(xiàn)會按固定間隔將其內(nèi)容刷新到磁盤。如果您是在本地運行應(yīng)用程序,那么該功能很有用,因為它將在您關(guān)閉服務(wù)器之后保存您的狀態(tài)。但是在運行測試時,如果每個測試都從干凈的數(shù)據(jù)存儲區(qū)開始,則編寫確定性測試將更容易,將狀態(tài)刷新至磁盤然后讀回可能會產(chǎn)生妨礙。我們將擴展 LocalServiceTestCase 來演示如何完成該操作:代碼import com.google.appengine.api.datastore.dev.LocalDatas

36、toreService;import com.google.appengine.tools.development.ApiProxyLocalImpl;public class LocalDatastoreTestCase extends LocalServiceTestCase Override public void setUp() throws Exception super.setUp(); ApiProxyLocalImpl proxy = (ApiProxyLocalImpl) ApiProxy.getDelegate(); proxy.setProperty(LocalDatastoreService.NO_STORAGE_PROPERTY, Boolean.TRUE.toString(); Override public void tearDown() throws Excepti

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論