Posted on 2012-04-28 12:03
寒武紀 閱讀(1538)
評論(1) 編輯 收藏 所屬分類:
測試 、
軟件架構 、
Flex
用Flex做企業應用將近有一年時間了,這個過程很累,在國內這方面的積累不多,真正有參考意義的資料的確非常少。經過一段長時間的摸索后,多少也積累了一點經驗,就最近的關于單元測試的想法做一點總結,由于涉及的知識較多,這里也只是給出個人的一種思路。
眾所周知,Flex的缺點是開發調試效率較低,而且它只是表現層的一種解決方案。在企業應用中最需要解決的是編譯生成的swf體積問題,我想任何客戶都很難接受一個企業應用全部打包在一個swf里,幾MB甚至幾十MB的初始化過程誰都無法接受,所以都必不可少地采用Module的加載方式,把不同的業務功能編譯成獨立的swf,需要用的時候再去加載。把核心功能、通信機制、公共組件設計成庫項目,編譯成swc做為RSL讓業務模塊共享調用,達到盡量減少業務模塊編譯體積的目的。在這方面如果用心優化的話,基本上可以控制到每個swf體積大概在200KB以內,這樣就算是互聯網方式部署,客戶訪問仍是可以接受的。
該結構圖給出了一種整體的設計方案,Flex的啟動肯定得有Application,這個是用戶初登錄后第一個加載的swf(登錄就不要用flex了,用jsp或是模板實現吧)。所以它負責加載你設計的整個框架,包含模塊加載機制、通信代理方式、基礎庫初始化等等,而和Java端的通信目前比較有效的仍然是blazeds,這個技術需要的介紹內容不在本文的范圍之內。關于通信接口的實現有一種非常有用的方式就是借用Java的動態代理理念,Spring有一個flex的擴展子項目叫做springactionscript,而這個項目又引用了as3commons的庫(類似于apache commons的一些公共組件)。為什么提及這個,因為flex本身的反射功能api非常難用,所以as3commons就做了擴展,它大大簡化了反射的使用,而且提供了一個bytecode的工具用于操作字節碼,它是實現動態代理的關鍵。至于為什么要動態代理?目的就是達到在寫和Java對接的接口時,可以只聲明接口,不需要實現類(得減少多少重復代碼呀?),而和Java對接接口我們又可以開發一個工具讓java code 自動轉成 as code,如果懂得Eclipse插件開發的話還可以進一步做一個插件,達到Java只寫一次就可以自動生成對應的flex接口,提高開發效率。 轉入正題,關于單元測試的概念,Flash Builder在4.5已經把flex unit作為內置庫了,這點和Eclipse把junit內置類似,而flex unit的使用網上有大量的資料介紹,這里也不多說。flex unit在測試as代碼還是不錯的,和junit測試一樣,提供了一些簡單的Assert斷言,但是你最痛苦的卻不是as的測試。企業開發的特點就是數據量不大,但是需求坑爹,經常變來變去,而且結構復雜,往往一張表很多字段,關聯子表,層級屬性多。而你如果選擇了Flex做了展示層的技術,那必定是看中它比HTML + CSS + JS更強的界面交互功能。的確,這點不容質疑,Flex Spark的皮膚機制的確提供了很多優秀的特點,不過如果你想純熟掌握它的整個機制,恐怕得花很多時間閱讀源代碼才行,而皮膚的制作整對別想讓美工獨自實現,它同樣是需要技術積累的,介紹它需要用幾個篇幅才足夠。任何技術方案都一樣,BS、CS、AIR在實現復雜界面時,對于開發人員來說,最痛苦的莫過于界面的單元測試。 痛苦在哪里?回看上面那幅架構圖,業務功能界面實現在Flex,業務邏輯在后臺Java,那么當二個團隊同時進行工作的時候,溝通就是最大的成本。解決溝通的問題就必須在先前設計時約定好接口和數據結構,那是會影響雙方團隊協調的關鍵因素。當雙方同時進行開發的時候,勢必存在前臺依賴后臺的情況,因為它能到達界面的前提得在整個框架載入后(并且可以初始化一堆數據,發生了通信),Java后臺還好說,依賴于spring和junit可以做到很好的單元測試。而flex就痛苦了,我沒有通訊啥都做不了呀! 如何設計單元測試?最大的出發點就是如何切掉和后臺通信連接,看下面的簡單結構圖
實現思路介紹: 1. 簡化Application加載過程 -- 可以套用你主程序中的加載過程,但是不需要你的主界面其它多余的元素,達到減少到達測試界面的多余步驟(盡可能少地減少鼠標和鍵盤操作) 2. 定義測試配置 -- 測試哪個模塊?哪個工作流程?你得通過配置的方式來定義,而不是每次都手寫代碼,才能方便你的成員使用你這個工具 3. 模擬后臺接口實現 -- 記得上面說的動態代理嗎?其實是為接口動態生成一個實現類,然后注入真正通信的實現代碼,例如WebService、HTTP,既然可以注入這些通信渠道,當然就可以注入本地實現類啦 4. 對象查看器 -- 這個是神馬?因為你都不要Java后臺了,每次操作一個界面后得提交數據吧?沒有后臺了,提交到哪里?你得必須把你的提交對象用界面展示出來吧?好吧,這個可是個難點! 我想這四個方面的原則無非就是:減少單元測試需要進行的步驟(最快到達測試界面),脫離后臺依賴(自己簡單模擬后臺實現,可惜flex沒有類似java的mock庫,悲劇!),如何查看提交到后臺的結果。 單元測試的目標:界面能正常加載、提交數據正常,如果二者都沒問題,那么聯調的時候就可以非常容易定位到是Flex的問題還是Java的問題!達到介分責任的目標,當然,如果你所在團隊是按模塊分的,也就是說flex和java都是同一個人做,那么就不存在責任問題。 怎么實現上面的四個步驟呢?簡要地介紹一下吧。 第1簡化application加載,其實你可以把第一張圖中的application加載機制拷貝過來,只是主界面可以做得非常簡單,比如不需要多余的控件(比如過長的菜單、當前登錄人、時間、一陀設置按鈕等),只留下最核心的能到達你測試界面的入口,至于怎么設計這個簡化版的application,那得發揮你本人的創造力,另外還得看具體的業務。
第2定義測試配置。模塊如何加載?通信接口本地模擬實現類定義?通過配置顯示在appliation做為觸發控件,這些你都得自定義一套xml之類的文件來配置吧,這個就需要技巧了,不能設計得太復雜,因為你的開發人員需要沿用你定義的規范來定義它需要測試的模塊,關于這方面的知識,可以參考spring加載配置文件方式、struts2加載定義文件等理念,有一個概念我比較推薦,就是struts2中的include配置文件,允許配置文件分散,讓大家提供代碼和文件時減少沖突,又可以套用你正常的加載機制。
第3模擬后臺接口實現。這個是比較煩的,模擬機制本身通過動態代理倒是不難實現,惡心的是你得自己動手用flex簡單實現一次后臺生成數據、處理數據的邏輯。這里我有個實踐的總結經驗分享,在前期你調試完的后臺接口證明是沒有問題的,那么可以混合使用,一部分調試過的接口可以直接用后臺,而新接口才本地模擬。一個原則就是后臺有的,已經證明穩定的就用后臺,沒有的或是后臺還沒有完成的你就自己模擬。
第4對象查看器。想想flex不能操作數據庫、由于安全限制不允許直接操作文件、無法讀取本地文件目錄。而你的測試數據也許會有關聯(特別是在工作流方面),所以你得想一個方案來保存你的對象結果,而且得以一種人性化的方式查看對象內容。且拋開數據存儲的問題,這個對象查看器如何設計就夠你頭疼的了,首先是對象得定義成一種格式,一種人可以看得懂的格式,比如xml,可以支持序列化和反序列化,你得去掉多余的無用屬性和訪問器。又得回到反射機制上了,序列化其實不難,難的是反序列化時如何正確地轉成原來的對象。列一種本人設計的結構: <xxx type="com.xx.oo.XXClass"> <aa type="String">aaa</aa> <bb type="Boolean">true</bb> <list type="mx.collection.ArrayCollenction"> .... </list> </xxx> 對象分簡單對象、復雜對象、動態對象等,如何表達這種結構和保證序列化時不丟失數據需要細心考慮。那么最后如何實現查看器呢?其實有一個參考的范例,就是Eclipse的“大綱”視圖,經過實踐的擴展,把樹視圖換成表格樹(這種控件原生沒有,有第三方的可以拿來修改),看個樣圖吧!
因為你關注的對象內容無法就是這三個方面,屬性名、值、和類型,又支持以樹方式導航對象,已經足夠你人眼分辯內容了。至于如何有效的保存測試數據,并且組織好結構,這個方面我目前也仍在思考中,未有較好的思路。 以上內容僅是出于本人的一種方案,也許有更好的實現方案,只是水平不足以超過這種認識,希望后續能進一步思考能實現更加完美的單元測試框架。 ST測試更關注的界面的自動化測試,這方面涉及的知識更多,一般公司是很難有財力和技術去支持做自動化測試,屬于比較高端的范圍,實現是很多回歸都靠測試團隊人肉在實現。 剛進場的時候戲就落幕