Flex在企業(yè)應(yīng)用中關(guān)于單元測(cè)試的一種設(shè)計(jì)思路
Posted on 2012-04-28 12:03 寒武紀(jì) 閱讀(1542) 評(píng)論(1) 編輯 收藏 所屬分類: 測(cè)試 、軟件架構(gòu) 、Flex 用Flex做企業(yè)應(yīng)用將近有一年時(shí)間了,這個(gè)過(guò)程很累,在國(guó)內(nèi)這方面的積累不多,真正有參考意義的資料的確非常少。經(jīng)過(guò)一段長(zhǎng)時(shí)間的摸索后,多少也積累了一點(diǎn)經(jīng)驗(yàn),就最近的關(guān)于單元測(cè)試的想法做一點(diǎn)總結(jié),由于涉及的知識(shí)較多,這里也只是給出個(gè)人的一種思路。
眾所周知,F(xiàn)lex的缺點(diǎn)是開(kāi)發(fā)調(diào)試效率較低,而且它只是表現(xiàn)層的一種解決方案。在企業(yè)應(yīng)用中最需要解決的是編譯生成的swf體積問(wèn)題,我想任何客戶都很難接受一個(gè)企業(yè)應(yīng)用全部打包在一個(gè)swf里,幾MB甚至幾十MB的初始化過(guò)程誰(shuí)都無(wú)法接受,所以都必不可少地采用Module的加載方式,把不同的業(yè)務(wù)功能編譯成獨(dú)立的swf,需要用的時(shí)候再去加載。把核心功能、通信機(jī)制、公共組件設(shè)計(jì)成庫(kù)項(xiàng)目,編譯成swc做為RSL讓業(yè)務(wù)模塊共享調(diào)用,達(dá)到盡量減少業(yè)務(wù)模塊編譯體積的目的。在這方面如果用心優(yōu)化的話,基本上可以控制到每個(gè)swf體積大概在200KB以內(nèi),這樣就算是互聯(lián)網(wǎng)方式部署,客戶訪問(wèn)仍是可以接受的。
眾所周知,F(xiàn)lex的缺點(diǎn)是開(kāi)發(fā)調(diào)試效率較低,而且它只是表現(xiàn)層的一種解決方案。在企業(yè)應(yīng)用中最需要解決的是編譯生成的swf體積問(wèn)題,我想任何客戶都很難接受一個(gè)企業(yè)應(yīng)用全部打包在一個(gè)swf里,幾MB甚至幾十MB的初始化過(guò)程誰(shuí)都無(wú)法接受,所以都必不可少地采用Module的加載方式,把不同的業(yè)務(wù)功能編譯成獨(dú)立的swf,需要用的時(shí)候再去加載。把核心功能、通信機(jī)制、公共組件設(shè)計(jì)成庫(kù)項(xiàng)目,編譯成swc做為RSL讓業(yè)務(wù)模塊共享調(diào)用,達(dá)到盡量減少業(yè)務(wù)模塊編譯體積的目的。在這方面如果用心優(yōu)化的話,基本上可以控制到每個(gè)swf體積大概在200KB以內(nèi),這樣就算是互聯(lián)網(wǎng)方式部署,客戶訪問(wèn)仍是可以接受的。

該結(jié)構(gòu)圖給出了一種整體的設(shè)計(jì)方案,F(xiàn)lex的啟動(dòng)肯定得有Application,這個(gè)是用戶初登錄后第一個(gè)加載的swf(登錄就不要用flex了,用jsp或是模板實(shí)現(xiàn)吧)。所以它負(fù)責(zé)加載你設(shè)計(jì)的整個(gè)框架,包含模塊加載機(jī)制、通信代理方式、基礎(chǔ)庫(kù)初始化等等,而和Java端的通信目前比較有效的仍然是blazeds,這個(gè)技術(shù)需要的介紹內(nèi)容不在本文的范圍之內(nèi)。關(guān)于通信接口的實(shí)現(xiàn)有一種非常有用的方式就是借用Java的動(dòng)態(tài)代理理念,Spring有一個(gè)flex的擴(kuò)展子項(xiàng)目叫做springactionscript,而這個(gè)項(xiàng)目又引用了as3commons的庫(kù)(類似于apache commons的一些公共組件)。為什么提及這個(gè),因?yàn)閒lex本身的反射功能api非常難用,所以as3commons就做了擴(kuò)展,它大大簡(jiǎn)化了反射的使用,而且提供了一個(gè)bytecode的工具用于操作字節(jié)碼,它是實(shí)現(xiàn)動(dòng)態(tài)代理的關(guān)鍵。至于為什么要?jiǎng)討B(tài)代理?目的就是達(dá)到在寫(xiě)和Java對(duì)接的接口時(shí),可以只聲明接口,不需要實(shí)現(xiàn)類(得減少多少重復(fù)代碼呀?),而和Java對(duì)接接口我們又可以開(kāi)發(fā)一個(gè)工具讓java code 自動(dòng)轉(zhuǎn)成 as code,如果懂得Eclipse插件開(kāi)發(fā)的話還可以進(jìn)一步做一個(gè)插件,達(dá)到Java只寫(xiě)一次就可以自動(dòng)生成對(duì)應(yīng)的flex接口,提高開(kāi)發(fā)效率。
轉(zhuǎn)入正題,關(guān)于單元測(cè)試的概念,F(xiàn)lash Builder在4.5已經(jīng)把flex unit作為內(nèi)置庫(kù)了,這點(diǎn)和Eclipse把junit內(nèi)置類似,而flex unit的使用網(wǎng)上有大量的資料介紹,這里也不多說(shuō)。flex unit在測(cè)試as代碼還是不錯(cuò)的,和junit測(cè)試一樣,提供了一些簡(jiǎn)單的Assert斷言,但是你最痛苦的卻不是as的測(cè)試。企業(yè)開(kāi)發(fā)的特點(diǎn)就是數(shù)據(jù)量不大,但是需求坑爹,經(jīng)常變來(lái)變?nèi)ィ医Y(jié)構(gòu)復(fù)雜,往往一張表很多字段,關(guān)聯(lián)子表,層級(jí)屬性多。而你如果選擇了Flex做了展示層的技術(shù),那必定是看中它比HTML + CSS + JS更強(qiáng)的界面交互功能。的確,這點(diǎn)不容質(zhì)疑,F(xiàn)lex Spark的皮膚機(jī)制的確提供了很多優(yōu)秀的特點(diǎn),不過(guò)如果你想純熟掌握它的整個(gè)機(jī)制,恐怕得花很多時(shí)間閱讀源代碼才行,而皮膚的制作整對(duì)別想讓美工獨(dú)自實(shí)現(xiàn),它同樣是需要技術(shù)積累的,介紹它需要用幾個(gè)篇幅才足夠。任何技術(shù)方案都一樣,BS、CS、AIR在實(shí)現(xiàn)復(fù)雜界面時(shí),對(duì)于開(kāi)發(fā)人員來(lái)說(shuō),最痛苦的莫過(guò)于界面的單元測(cè)試。
痛苦在哪里?回看上面那幅架構(gòu)圖,業(yè)務(wù)功能界面實(shí)現(xiàn)在Flex,業(yè)務(wù)邏輯在后臺(tái)Java,那么當(dāng)二個(gè)團(tuán)隊(duì)同時(shí)進(jìn)行工作的時(shí)候,溝通就是最大的成本。解決溝通的問(wèn)題就必須在先前設(shè)計(jì)時(shí)約定好接口和數(shù)據(jù)結(jié)構(gòu),那是會(huì)影響雙方團(tuán)隊(duì)協(xié)調(diào)的關(guān)鍵因素。當(dāng)雙方同時(shí)進(jìn)行開(kāi)發(fā)的時(shí)候,勢(shì)必存在前臺(tái)依賴后臺(tái)的情況,因?yàn)樗艿竭_(dá)界面的前提得在整個(gè)框架載入后(并且可以初始化一堆數(shù)據(jù),發(fā)生了通信),Java后臺(tái)還好說(shuō),依賴于spring和junit可以做到很好的單元測(cè)試。而flex就痛苦了,我沒(méi)有通訊啥都做不了呀!
如何設(shè)計(jì)單元測(cè)試?最大的出發(fā)點(diǎn)就是如何切掉和后臺(tái)通信連接,看下面的簡(jiǎn)單結(jié)構(gòu)圖

實(shí)現(xiàn)思路介紹:
1. 簡(jiǎn)化Application加載過(guò)程 -- 可以套用你主程序中的加載過(guò)程,但是不需要你的主界面其它多余的元素,達(dá)到減少到達(dá)測(cè)試界面的多余步驟(盡可能少地減少鼠標(biāo)和鍵盤(pán)操作)
2. 定義測(cè)試配置 -- 測(cè)試哪個(gè)模塊?哪個(gè)工作流程?你得通過(guò)配置的方式來(lái)定義,而不是每次都手寫(xiě)代碼,才能方便你的成員使用你這個(gè)工具
3. 模擬后臺(tái)接口實(shí)現(xiàn) -- 記得上面說(shuō)的動(dòng)態(tài)代理嗎?其實(shí)是為接口動(dòng)態(tài)生成一個(gè)實(shí)現(xiàn)類,然后注入真正通信的實(shí)現(xiàn)代碼,例如WebService、HTTP,既然可以注入這些通信渠道,當(dāng)然就可以注入本地實(shí)現(xiàn)類啦
4. 對(duì)象查看器 -- 這個(gè)是神馬?因?yàn)槟愣疾灰狫ava后臺(tái)了,每次操作一個(gè)界面后得提交數(shù)據(jù)吧?沒(méi)有后臺(tái)了,提交到哪里?你得必須把你的提交對(duì)象用界面展示出來(lái)吧?好吧,這個(gè)可是個(gè)難點(diǎn)!
我想這四個(gè)方面的原則無(wú)非就是:減少單元測(cè)試需要進(jìn)行的步驟(最快到達(dá)測(cè)試界面),脫離后臺(tái)依賴(自己簡(jiǎn)單模擬后臺(tái)實(shí)現(xiàn),可惜flex沒(méi)有類似java的mock庫(kù),悲?。。?,如何查看提交到后臺(tái)的結(jié)果。 單元測(cè)試的目標(biāo):界面能正常加載、提交數(shù)據(jù)正常,如果二者都沒(méi)問(wèn)題,那么聯(lián)調(diào)的時(shí)候就可以非常容易定位到是Flex的問(wèn)題還是Java的問(wèn)題!達(dá)到介分責(zé)任的目標(biāo),當(dāng)然,如果你所在團(tuán)隊(duì)是按模塊分的,也就是說(shuō)flex和java都是同一個(gè)人做,那么就不存在責(zé)任問(wèn)題。
怎么實(shí)現(xiàn)上面的四個(gè)步驟呢?簡(jiǎn)要地介紹一下吧。
第1簡(jiǎn)化application加載,其實(shí)你可以把第一張圖中的application加載機(jī)制拷貝過(guò)來(lái),只是主界面可以做得非常簡(jiǎn)單,比如不需要多余的控件(比如過(guò)長(zhǎng)的菜單、當(dāng)前登錄人、時(shí)間、一陀設(shè)置按鈕等),只留下最核心的能到達(dá)你測(cè)試界面的入口,至于怎么設(shè)計(jì)這個(gè)簡(jiǎn)化版的application,那得發(fā)揮你本人的創(chuàng)造力,另外還得看具體的業(yè)務(wù)。
第2定義測(cè)試配置。模塊如何加載?通信接口本地模擬實(shí)現(xiàn)類定義?通過(guò)配置顯示在appliation做為觸發(fā)控件,這些你都得自定義一套xml之類的文件來(lái)配置吧,這個(gè)就需要技巧了,不能設(shè)計(jì)得太復(fù)雜,因?yàn)槟愕拈_(kāi)發(fā)人員需要沿用你定義的規(guī)范來(lái)定義它需要測(cè)試的模塊,關(guān)于這方面的知識(shí),可以參考spring加載配置文件方式、struts2加載定義文件等理念,有一個(gè)概念我比較推薦,就是struts2中的include配置文件,允許配置文件分散,讓大家提供代碼和文件時(shí)減少?zèng)_突,又可以套用你正常的加載機(jī)制。
第3模擬后臺(tái)接口實(shí)現(xiàn)。這個(gè)是比較煩的,模擬機(jī)制本身通過(guò)動(dòng)態(tài)代理倒是不難實(shí)現(xiàn),惡心的是你得自己動(dòng)手用flex簡(jiǎn)單實(shí)現(xiàn)一次后臺(tái)生成數(shù)據(jù)、處理數(shù)據(jù)的邏輯。這里我有個(gè)實(shí)踐的總結(jié)經(jīng)驗(yàn)分享,在前期你調(diào)試完的后臺(tái)接口證明是沒(méi)有問(wèn)題的,那么可以混合使用,一部分調(diào)試過(guò)的接口可以直接用后臺(tái),而新接口才本地模擬。一個(gè)原則就是后臺(tái)有的,已經(jīng)證明穩(wěn)定的就用后臺(tái),沒(méi)有的或是后臺(tái)還沒(méi)有完成的你就自己模擬。
第4對(duì)象查看器。想想flex不能操作數(shù)據(jù)庫(kù)、由于安全限制不允許直接操作文件、無(wú)法讀取本地文件目錄。而你的測(cè)試數(shù)據(jù)也許會(huì)有關(guān)聯(lián)(特別是在工作流方面),所以你得想一個(gè)方案來(lái)保存你的對(duì)象結(jié)果,而且得以一種人性化的方式查看對(duì)象內(nèi)容。且拋開(kāi)數(shù)據(jù)存儲(chǔ)的問(wèn)題,這個(gè)對(duì)象查看器如何設(shè)計(jì)就夠你頭疼的了,首先是對(duì)象得定義成一種格式,一種人可以看得懂的格式,比如xml,可以支持序列化和反序列化,你得去掉多余的無(wú)用屬性和訪問(wèn)器。又得回到反射機(jī)制上了,序列化其實(shí)不難,難的是反序列化時(shí)如何正確地轉(zhuǎn)成原來(lái)的對(duì)象。列一種本人設(shè)計(jì)的結(jié)構(gòu):
<xxx type="com.xx.oo.XXClass">
<aa type="String">aaa</aa>
<bb type="Boolean">true</bb>
<list type="mx.collection.ArrayCollenction">
....
</list>
</xxx>
對(duì)象分簡(jiǎn)單對(duì)象、復(fù)雜對(duì)象、動(dòng)態(tài)對(duì)象等,如何表達(dá)這種結(jié)構(gòu)和保證序列化時(shí)不丟失數(shù)據(jù)需要細(xì)心考慮。那么最后如何實(shí)現(xiàn)查看器呢?其實(shí)有一個(gè)參考的范例,就是Eclipse的“大綱”視圖,經(jīng)過(guò)實(shí)踐的擴(kuò)展,把樹(shù)視圖換成表格樹(shù)(這種控件原生沒(méi)有,有第三方的可以拿來(lái)修改),看個(gè)樣圖吧!

因?yàn)槟汴P(guān)注的對(duì)象內(nèi)容無(wú)法就是這三個(gè)方面,屬性名、值、和類型,又支持以樹(shù)方式導(dǎo)航對(duì)象,已經(jīng)足夠你人眼分辯內(nèi)容了。至于如何有效的保存測(cè)試數(shù)據(jù),并且組織好結(jié)構(gòu),這個(gè)方面我目前也仍在思考中,未有較好的思路。
以上內(nèi)容僅是出于本人的一種方案,也許有更好的實(shí)現(xiàn)方案,只是水平不足以超過(guò)這種認(rèn)識(shí),希望后續(xù)能進(jìn)一步思考能實(shí)現(xiàn)更加完美的單元測(cè)試框架。
ST測(cè)試更關(guān)注的界面的自動(dòng)化測(cè)試,這方面涉及的知識(shí)更多,一般公司是很難有財(cái)力和技術(shù)去支持做自動(dòng)化測(cè)試,屬于比較高端的范圍,實(shí)現(xiàn)是很多回歸都靠測(cè)試團(tuán)隊(duì)人肉在實(shí)現(xiàn)。
剛進(jìn)場(chǎng)的時(shí)候戲就落幕