亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Flex > 正文

24.8.用FlexUnit測試可視化組件

2024-09-08 18:16:50
字體:
來源:轉載
供稿:網友
24.8.1. 問題
我需要測試可視化組件
24.8.2. 解決辦法
展示將組件放在可視體系中然后測試它。
24.8.3. 討論
有人認為可視組件的測試已偏離了單元測試的目的,因為它們很難被獨立出來進行測試,以便能控制測試條件。測試功能豐富的Flex框架組件是很復雜的,比如怎樣確定某個方法是否被正確調用。樣式和父容器也會影響一個組件的行為。因此,你最好是用自動化功能測試的方法來測試可視組件。

在測試一個可視組件之前,該組件必須通過了各種生命周期步驟。當組件被添加到顯示體系后Flex框架會自動進行處理。TestCases雖然不是一個可視組件,這意味著組件必須與外部的TestCase相關聯。這種外部關聯意味著無論測試失敗還是成功你都必須小心清理善后工作;否則可能會影響到其他組件的測試。

24.8.3.1. 組件測試模式
獲得顯示對象引用最簡單的方法是使用Application.application。因為TestCase是運行Flex應用程序之上,它是一個單例實例??梢暯M件的創建和激活并不是一個同步的行為;在可被測試之前, TestCase 需要等待組件進入一個已知的狀態。通過使用addAsync 等待FlexEvent.CREATION_COMPLETE事件是最簡單的方法知道新創建的組件已進入已知狀態。要確保一個TestCase方法不會影響到其他正在運行的TestCase方法,被創建的組件在被移除前必須清理和釋放任何外部引用。使用tearDown方法和類實例變量是完成這兩個任務的最好方法。下面的例子代碼演示Tile組件的創建,連接,激活和清理:
+展開
-ActionScript
package mx.containers
{
import flexunit.framework.TestCase;
import mx.core.Application;
import mx.events.FlexEvent;
public class TileTest extends TestCase
{
// class variable allows tearDown() to access the instance
private var _tile:Tile;
override public function tearDown():void
{
try
{
Application.application.removeChild(_tile);
}
catch (argumentError:ArgumentError)
{
// safe to ignore, just means component was never added
}
_tile = null;
}
public function testTile():void
{
_tile = new Tile();
_tile.addEventListener(FlexEvent.CREATION_COMPLETE,addAsync(verifyTile, 1000));
Application.application.addChild(_tile);
}
private function verifyTile(flexEvent:FlexEvent):void{
// component now ready for testing
assertTrue(_tile.initialized);
}
}
}

這里需要注意的關鍵點是定義了一個類變量,允許tearDown方法引用這個被創建和添加到Application.application的實例對象。另外組件被添加到Application.application可能還沒有成功,這就是為什么tearDown方法中的removeChild調用被放置在try...catch塊中以防止拋出任何異常。測試方法使用addAsync在運行測試之前進行等待,直到組件進入一個穩定的狀態。

24.8.3.2. 組件創建測試
雖然你可以手動調用測試和各種其他Flex框架組件方法,測試將更好的模擬對象所運行的環境。不像單元測試,組件所連接外部環境將不能被嚴格控制,這意味著你必須集中于組件的測試而不能顧及周圍環境。例如,早先創建的Tile容器的布局邏輯可被測試:
+展開
-ActionScript
public function testTileLayout():void
{
_tile = new Tile();
var canvas:Canvas = new Canvas();
canvas.width = 100;
canvas.height = 100;
_tile.addChild(canvas);
canvas = new Canvas();
canvas.width = 50;
canvas.height = 50;
_tile.addChild(canvas);
canvas = new Canvas();
canvas.width = 150;
canvas.height = 50;
_tile.addChild(canvas);
_tile.addEventListener(FlexEvent.CREATION_COMPLETE,addAsync(verifyTileLayout, 1000));
Application.application.addChild(_tile);
}
private function verifyTileLayout(flexEvent:FlexEvent):void
{
var horizontalGap:int =int(_tile.getStyle("horizontalGap"));
var verticalGap:int =int(_tile.getStyle("verticalGap"));
assertEquals(300 + horizontalGap, _tile.width);
assertEquals(200 + verticalGap, _tile.height);
assertEquals(3, _tile.numChildren);
assertEquals(0, _tile.getChildAt(0).x);
assertEquals(0, _tile.getChildAt(0).y);
assertEquals(150 + horizontalGap,
_tile.getChildAt(1).x);
assertEquals(0, _tile.getChildAt(1).y);
assertEquals(0, _tile.getChildAt(2).x);
assertEquals(100 + verticalGap, _tile.getChildAt(2).y);
}

這個例子中,三個大小不同的子組件被添加到Tile。根據Tile布局邏輯,這個例子應該創建一個2 x 2 的網格并使每個網格的寬度和高度最大化以容納子組件。Verify方法斷言默認邏輯將會生產的結果。重要的是要注意到測試只注重于組件所使用到的邏輯。這不是測試布局是否看起來足夠好,而只是其行為與文檔相匹配。另外重要的一點需要注意,就是關于當前層級的組件測試會影響到在其之上的組件樣式。這個測試方法在它創建實例時可以設置樣式值以便確認該值是否被使用過。

24.8.3.3. Postcreation 測試
組件創建后,額外的變化會讓測試變得很困難。通常使用FlexEvent.UPDATE_COMPLETE事件,但組件的一個簡單變化會多次觸發此事件。雖然可以建立邏輯以正確處理這多個事件,但是TestCase除了測試組件內邏輯并不會區分Flex框架事件和UI更新邏輯。因此集中于組件邏輯的測試設計確實是一門藝術。這就是為什么要在這個級別進行組件測試而不是單元測試。

下面的例子添加了另外的子組件到先前創建的Tile,檢測發生的變化:
+展開
-ActionScript
// class variable to track the last addAsync() Function instance
private var _async:Function;
public function testTileLayoutChangeAfterCreate():void
{
_tile = new Tile();
var canvas:Canvas = new Canvas();
canvas.width = 100;
canvas.height = 100;
_tile.addChild(canvas);
canvas = new Canvas();
canvas.width = 50;
canvas.height = 50;
_tile.addChild(canvas);
canvas = new Canvas();
canvas.width = 150;
canvas.height = 50;
_tile.addChild(canvas);
_tile.addEventListener(FlexEvent.CREATION_COMPLETE,addAsync(verifyTileLayoutAfterCreate, 1000));
Application.application.addChild(_tile);
}
private function
verifyTileLayoutAfterCreate(flexEvent:FlexEvent):void
{
var horizontalGap:int =int(_tile.getStyle("horizontalGap"));
var verticalGap:int =int(_tile.getStyle("verticalGap"));
assertEquals(300 + horizontalGap, _tile.width);
assertEquals(200 + verticalGap, _tile.height);
assertEquals(3, _tile.numChildren);
assertEquals(0, _tile.getChildAt(0).x);
assertEquals(0, _tile.getChildAt(0).y);
assertEquals(150 + horizontalGap,
_tile.getChildAt(1).x);
assertEquals(0, _tile.getChildAt(1).y);
assertEquals(0, _tile.getChildAt(2).x);
assertEquals(100 + verticalGap, _tile.getChildAt(2).y);
var canvas:Canvas = new Canvas();
canvas.width = 200;
canvas.height = 100;
_tile.addChild(canvas);
_async = addAsync(verifyTileLayoutChanging, 1000);
_tile.addEventListener(FlexEvent.UPDATE_COMPLETE,
_async);
}
private function
verifyTileLayoutChanging(flexEvent:FlexEvent):void
{
_tile.removeEventListener(FlexEvent.UPDATE_COMPLETE,
_async);
_tile.addEventListener(FlexEvent.UPDATE_COMPLETE,
addAsync
(verifyTileLayoutChangeAfterCreate, 1000));
}
private function verifyTileLayoutChangeAfterCreate(flexEvent:FlexEvent):void{
var horizontalGap:int =int(_tile.getStyle("horizontalGap"));
var verticalGap:int =int(_tile.getStyle("verticalGap"));
assertEquals(400 + horizontalGap, _tile.width);
assertEquals(200 + verticalGap, _tile.height);
assertEquals(4, _tile.numChildren);
assertEquals(0, _tile.getChildAt(0).x);
assertEquals(0, _tile.getChildAt(0).y);
assertEquals(200 + horizontalGap,
_tile.getChildAt(1).x);
assertEquals(0, _tile.getChildAt(1).y);
assertEquals(0, _tile.getChildAt(2).x);
assertEquals(100 + verticalGap, _tile.getChildAt(2).y);
assertEquals(200 + horizontalGap,
_tile.getChildAt(3).x);
assertEquals(100 + verticalGap, _tile.getChildAt(3).y);
}

事件處理邏輯現在使用一個類變量來跟蹤最后通過addAsync添加的異步函數,這是為了允許改監聽器可被移除并添加一個不同的監聽器來處理第二次觸發的同類事件。如果這時另一個變化發生,將會觸發另一個FlexEvent.UPDATE_COMPLETE,verifyTileLayoutChanging方法也必須存儲它的addAsync函數為了它能被移除。如果Flex框架邏輯改變了如何觸發事件,那這一鏈式事件處理就顯得很脆弱了,整個代碼測試將會導致失敗。這個測試沒有處理這兩個觸發的FlexEvent.UPDATE_COMPLETE事件為了組件能順利完成子組件的布局任務;在這個級別試圖捕捉組件邏輯會產生意想不到的效果。如果在中間狀態verifyTileLayoutChanging中捕捉組件邏輯,在這個方法中的斷言將發揮作用,如果事件沒有被正確觸發,這些變化的事件將會保證此測試失敗。

雖然組件也會觸發額外的事件,如Event.RESIZE,但是該事件所在的組件狀態通常是不穩定的。正如處在Event.RESIZE的Tile那樣,組件的寬度發生變化,但是其子組件的位置卻還沒有。另外還可能有這樣的排隊操作,當要移除顯示層級中的組件時操作隊列中卻要試圖訪問該組件,這將會導致錯誤。當測試那些采用同步方式更新邏輯的組件,移除其他監聽器還需要的組件時要盡量避免發生這些問題。換句話說,被測試組件發出的事件要清晰表明組件的變化已完全實現。不管你選擇什么方法處理這種情況,請記住有哪些方法是可靠的,有哪些測試行為是脫離組件的。

24.8.3.4. 根據時間測試
如果組件一下子產生了很多復雜的變化,維持事件的數量和順序將會非常困難。除了等待特定的事件外,另一個辦法就是去等待一段時間。這個方法可以輕松的處理多個被更新的對象或組件(使用Effect實例,在某個已知時間內播放)?;跁r間的測試最主要的缺點就是如果測試環境的速度和資源發生改變的話可能會導致誤報。等待一個固定時間也意味著整個TestSuite的所花時間將比添加異步或事件驅動的測試多出不少。

下面的代碼是把之前的Tile例子用基于時間的觸發器改寫一邊:
+展開
-ActionScript
private function waitToTest(listener:Function,waitTime:int):void
{
var timer:Timer = new Timer(waitTime, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE,addAsync(listener,waitTime + 250));
timer.start();
}
public function testTileLayoutWithTimer():void
{
_tile = new Tile();
var canvas:Canvas = new Canvas();
canvas.width = 100;
canvas.height = 100;
_tile.addChild(canvas);
canvas = new Canvas();
canvas.width = 50;
canvas.height = 50;
_tile.addChild(canvas);
canvas = new Canvas();
canvas.width = 150;
canvas.height = 50;
_tile.addChild(canvas);
Application.application.addChild(_tile);
waitToTest(verifyTileLayoutCreateWithTimer, 500);
}
private function verifyTileLayoutCreateWithTimer(timerEvent:TimerEvent):void{
var horizontalGap:int =int(_tile.getStyle("horizontalGap"));
var verticalGap:int =int(_tile.getStyle("verticalGap"));
assertEquals(300 + horizontalGap, _tile.width);
assertEquals(200 + verticalGap, _tile.height);
assertEquals(3, _tile.numChildren);
assertEquals(0, _tile.getChildAt(0).x);
assertEquals(0, _tile.getChildAt(0).y);
assertEquals(150 + horizontalGap,
_tile.getChildAt(1).x);
assertEquals(0, _tile.getChildAt(1).y);
assertEquals(0, _tile.getChildAt(2).x);
assertEquals(100 + verticalGap, _tile.getChildAt(2).y);
var canvas:Canvas = new Canvas();
canvas.width = 200;
canvas.height = 100;
_tile.addChild(canvas);
waitToTest(verifyTileLayoutChangeWithTimer, 500);
}
private function verifyTileLayoutChangeWithTimer(timerEvent:TimerEvent):void{
var horizontalGap:int =int(_tile.getStyle("horizontalGap"));
var verticalGap:int =int(_tile.getStyle("verticalGap"));
assertEquals(400 + horizontalGap, _tile.width);
assertEquals(200 + verticalGap, _tile.height);
assertEquals(4, _tile.numChildren);
assertEquals(0, _tile.getChildAt(0).x);
assertEquals(0, _tile.getChildAt(0).y);
assertEquals(200 + horizontalGap,
_tile.getChildAt(1).x);
assertEquals(0, _tile.getChildAt(1).y);
assertEquals(0, _tile.getChildAt(2).x);
assertEquals(100 + verticalGap, _tile.getChildAt(2).y);
assertEquals(200 + horizontalGap,
_tile.getChildAt(3).x);
assertEquals(100 + verticalGap, _tile.getChildAt(3).y);
}

和之前的測試例子,能快速響應觸發的事件不同,這個版本的測試將最少要1秒時間,更多的時間被用在定時器延時上, 在這期間調用addAsync 處理。之前例子中包裝FlexEvent.UPDATE_COMPLETE監聽器的中間方法被移除了,但在其他測試代碼中保持一致。

24.8.3.5. 使用程序化的視覺斷言
獲取渲染組件的原始位圖數據能力能很方便的以編程方式來驗證可視組件的某個方面。這里有個例子將測試組件的背景和邊框樣式是如何改變的。創建組件實例后,可以捕捉其位圖數據并進行檢查。下面的例子通過添加Canvas邊框來測試能產生預期效果:
+展開
-ActionScript
package mx.containers
{
import flash.display.BitmapData;
import flexunit.framework.TestCase;
import mx.core.Application;
import mx.events.FlexEvent;
public class CanvasTest extends TestCase
{
// class variable allows tearDown() to access the instance
private var _canvas:Canvas;
override public function tearDown():void
{
try
{
Application.application.removeChild(_canvas);
}
catch (argumentError:ArgumentError)
{
// safe to ignore, just means component was never added
}
_canvas = null;
}
private function captureBitmapData():BitmapData
{
var bitmapData:BitmapData = new BitmapData(_canvas.width, _canvas.height);
bitmapData.draw(_canvas);
return bitmapData;
}
public function testBackgroundColor():void
{
_canvas = new Canvas();
_canvas.width = 10;
_canvas.height = 10;
_canvas.setStyle("backgroundColor", 0xFF0000);
_canvas.addEventListener(FlexEvent.CREATION_COMPLETE,addAsync(verifyBackgroundColor, 1000));
Application.application.addChild(_canvas);
}
private function
verifyBackgroundColor(flexEvent:FlexEvent):void
{
var bitmapData:BitmapData = captureBitmapData();
for (var x:int = 0; x < bitmapData.width; x++)
{
for (var y:int = 0; y < bitmapData.height; y++)
{
assertEquals("Pixel (" + x + ", " + y + ")",0xFF0000, bitmapData. getPixel(x, y));
}
}
}
public function testBorder():void
{
_canvas = new Canvas();
_canvas.width = 10;
_canvas.height = 10;
_canvas.setStyle("backgroundColor", 0xFF0000);
_canvas.setStyle("borderColor", 0x00FF00);
_canvas.setStyle("borderStyle""solid");
_canvas.setStyle("borderThickness", 1);
_canvas.addEventListener(FlexEvent.CREATION_COMPLETE,
addAsync(verifyBorder, 1000));
Application.application.addChild(_canvas);
}
private function verifyBorder(flexEvent:FlexEvent):void
{
var bitmapData:BitmapData = captureBitmapData();
for (var x:int = 0; x < bitmapData.width; x++)
{
for (var y:int = 0; y < bitmapData.height; y++)
{
if ((x == 0) || (y == 0) || (x ==
bitmapData.width - 1) || (y == bitmapData.height - 1))
{
assertEquals("Pixel (" + x + ", " + y + ")",
0x00FF00,bitmapData.getPixel(x, y));
}
else
{
assertEquals("Pixel (" + x + ", " + y + ")",0xFF0000,bitmapData.getPixel(x, y));
}
}
}
}
}
}

testBackgroundColor方法驗證已設置背景顏色的Canvas的所有像素。testBorder方法驗證何時邊框被添加到Canvas,外邊框的像素值轉換為邊框顏色而其他所以像素仍保持背景色。捕獲位圖數據是在captureBitmapData方法中進行,使用它可以繪制任何Flex組件到BitmapData實例上。這是一項很強大的技術,可以用來驗證程序化的皮膚或其他很難進行單元測試的可視組件。

還有另一種方法測試組件的外觀。請到http://code.google.com/p/visualflexunit/看看Visual FlexUnit。

24.8.3.6. 隱藏被測試組件
添加測試組件到Application.application的一個副作用就是它將被渲染處理。這將導致當測試正在運行,組件正在被添加和移除時FlexUnit測試很難進行調整和重定位。要排除這個情況,你可以通過設置組件的visible和includeInLayout屬性為false來隱藏被測試組件。例如,如果要隱藏之前代碼中的Canvas的話,添加下面的代碼:
+展開
-ActionScript
_canvas.visible = false;
_canvas.includeInLayout = false;
Application.application.addChild(_canvas);
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
在线成人中文字幕| 91在线色戒在线| 久热精品视频在线免费观看| 亚洲欧美国产一本综合首页| 久久99热精品这里久久精品| 日韩美女在线观看一区| 日韩电影中文字幕| 国产精品国产自产拍高清av水多| 欧美日韩在线观看视频| 欧美xxxx综合视频| 亚洲精品成人久久| 日韩精品免费在线视频| 高跟丝袜一区二区三区| 亚洲男人天堂网| 国产精品久久91| 亚洲福利小视频| 视频一区视频二区国产精品| 久久久久久久91| 国产精品18久久久久久麻辣| 国产婷婷色综合av蜜臀av| 久久久91精品国产一区不卡| 91丨九色丨国产在线| 亚洲理论电影网| 国内精久久久久久久久久人| 91天堂在线观看| 91免费在线视频| 国产成人啪精品视频免费网| 国产精品视频永久免费播放| 成人免费黄色网| 九九精品视频在线| 午夜精品久久久久久久久久久久久| 欧美日韩中文在线| 成人精品久久一区二区三区| 亚洲欧美激情四射在线日| 欧美国产精品人人做人人爱| 亚洲视频日韩精品| 亚洲缚视频在线观看| 日韩有码在线电影| 欧美综合一区第一页| 国产suv精品一区二区三区88区| 亚洲国产精品电影在线观看| 国产成人精品一区| 奇门遁甲1982国语版免费观看高清| 黄色91在线观看| 欧美性极品xxxx做受| 亚洲xxxx18| 97精品免费视频| 亚洲国产私拍精品国模在线观看| 久久精品视频一| 91精品久久久久久久久久| 国产成人av在线播放| 亚洲福利视频网站| 91麻豆国产语对白在线观看| 日韩av影院在线观看| 久久精视频免费在线久久完整在线看| 欧美日韩综合视频| 97福利一区二区| 欧美巨猛xxxx猛交黑人97人| 国产主播喷水一区二区| 国产精品中文在线| 日韩va亚洲va欧洲va国产| 国产成人jvid在线播放| 欧美国产精品va在线观看| 中文字幕免费精品一区| 久久视频精品在线| 欧美性做爰毛片| 国产欧美日韩精品在线观看| 国产成人短视频| 久久九九全国免费精品观看| 久久精品国产69国产精品亚洲| 久久九九热免费视频| 78m国产成人精品视频| 宅男66日本亚洲欧美视频| 色系列之999| 日本欧美一级片| 午夜精品在线观看| 92福利视频午夜1000合集在线观看| 性欧美激情精品| 亚洲精品国产拍免费91在线| 日韩欧美有码在线| 日韩av第一页| 亚洲国产欧美一区二区丝袜黑人| 精品久久久91| 久久亚洲影音av资源网| 福利微拍一区二区| 国产视频一区在线| 日韩免费不卡av| 欧美黄色成人网| 国产欧美亚洲精品| 欧美一区二区视频97| 国产亚洲欧美另类中文| 久久香蕉国产线看观看网| 欧美极品欧美精品欧美视频| 伊人伊成久久人综合网小说| 日韩精品中文在线观看| 麻豆精品精华液| 亚洲女人被黑人巨大进入| 亚洲最大av网站| 亚洲精品久久久久中文字幕二区| 日韩美女视频在线观看| 国产婷婷色综合av蜜臀av| 色综合久久久久久中文网| 国产亚洲精品综合一区91| 中文字幕少妇一区二区三区| 精品一区二区三区四区| 亚洲黄色有码视频| 欧美亚洲另类激情另类| 亚洲裸体xxxx| 欧洲s码亚洲m码精品一区| 黄色成人在线免费| 国产精品h在线观看| 亚洲国产女人aaa毛片在线| 国产精品成人国产乱一区| 亚洲人成绝费网站色www| 91在线免费网站| 欧美性一区二区三区| 中文字幕久久久av一区| 2019中文字幕免费视频| 国产成人精品一区二区三区| 精品国产一区二区三区久久久| 国产97在线视频| 欧美高跟鞋交xxxxxhd| 91深夜福利视频| 精品精品国产国产自在线| 久久精品中文字幕免费mv| 国产午夜精品一区理论片飘花| 92福利视频午夜1000合集在线观看| 亚洲精品之草原avav久久| 精品一区二区三区三区| 精品欧美一区二区三区| 国产综合福利在线| 亚洲毛茸茸少妇高潮呻吟| 久久久亚洲欧洲日产国码aⅴ| 亚洲剧情一区二区| 国产精自产拍久久久久久| 精品久久久久久久久久ntr影视| 亚洲国产精品嫩草影院久久| 亚洲第一福利网站| 国产精品久久久久久网站| 青草青草久热精品视频在线网站| 国产精品久久久久久久9999| 日韩在线免费高清视频| 91免费视频网站| 一区二区三区美女xx视频| 欧美高清自拍一区| 欧洲s码亚洲m码精品一区| 久久精品99无色码中文字幕| 亚洲精品在线看| 亚洲精品国产品国语在线| 亚洲男人7777| 久久久久免费精品国产| 97色在线视频观看| 亚洲国产欧美一区二区三区久久| 亚洲丝袜在线视频| 91精品国产自产91精品| 国产亚洲精品91在线| 91免费精品国偷自产在线| 日韩精品视频在线观看免费| 欧美性jizz18性欧美| 久久精品电影网| 国产va免费精品高清在线观看| 欧美中文字幕在线视频| 91在线国产电影| 精品国产拍在线观看|