2014年5月5日 星期一

[AS] JenKins 整合我自己的 unit test 類別

本來以為在 FB 中的 ANT 可以正常運行 正常結束 就好了

如圖 :

結果在 JenKins 中確無法有效停止!

所以選擇用 ADL
首先遇到的問題是
原因是 adl 的版本和編譯的版本不同!

像我的 adl 是 3.1
但是我 IDE 產生的確是

所以會有問題 !

只要更新 adl  的版本 或是 修改 app.xml 就可以解決!

同 fdb 我也怕會有跑不停的問題!

所以我也加了 離開的函式!

那就只要讓 這個 air 程式去讀取編譯出來的 swf 然後接收

是否有錯, 有錯就寫報告 沒錯就不寫報告!

當然在 IDE 介面下都是沒有問題的!

但是在 JenKins 的環境下跑 確是會出事!

問題是出在匿名使用者


最後調整 將檔案存在 使用者目錄 (File.userDirectory)

如果有錯誤才輸出檔案 沒錯誤就不輸出檔案!

成功的情況如下
失敗情況如下




將我的 unit test 整合到 JenKins 上 並且自動發信的部分

已經全部結束 !!

其中我遇到的問題大部分都在上面陳述了

下面是我查詢的資料
ADL
http://labs.mstudio.com/?p=226
http://stackoverflow.com/questions/15428278/adl-error-while-loading-initial-content-adobe-air

如果想一勞永逸解決問題 就去更新ADL 相關的更新如下
http://helpx.adobe.com/x-productkb/multi/how-overlay-air-sdk-flex-sdk.html
http://helpx.adobe.com/flash-builder/kb/overlay-air-sdk-flash-builder.htmlhttp://helpx.adobe.com/flash-builder/kb/overlay-air-sdk-flash-builder.html

ANT 判斷
http://ant.apache.org/manual/index.html
http://www.ogshoppingmall.com/list.asp?id=49546
http://ant.apache.org/manual/Tasks/fail.html

as 相關資料
http://help.adobe.com/zh_TW/FlashPlatform/reference/actionscript/3/flash/filesystem/File.html
http://help.adobe.com/zh_TW/air/build/WS5b3ccc516d4fbf351e63e3d118666ade46-7fd9.html
http://help.adobe.com/zh_TW/air/build/WS5b3ccc516d4fbf351e63e3d118666ade46-7fd7.html

2014年4月27日 星期日

MVC,MVP,MVVM,MVFM 的比較和架構


今天因為在想一些架構上的問題 !

所以就找了一些東西看!

先講一下我看完一些資料後我自己的了解!

Model-View-Controller

的整個流程是

View <-> Controller -> Model -> View

View 被使用者操作 和 cotroller 互相作用 !

如果有 Cotroller 會通知 Model 作一些處理

Model 會通知 View 作一些改變!

為了將 循環 切斷 將切分得更乾淨!

產生了 Model - View - Presenter

Model <-> Presenter <-> View

View 和 Model 完全的切開了 !

但是更新資料卻要透過 Presenter  傳遞 !

基於 MVP 的架構 又多了一種拆分方式!

Model-View-ViewModel

這是一種特化的 MVP 拆分方式!

針對 View 去拆分 Presenter

讓 View 的流程更順 ~~

Model -> ViewModel <-> View

因為針對 View 去拆分 所以 ViewModel 重用的可能性變得很低

所以出現了

Model - View- FunctionModel 的拆分方法

把 針對 View 拆分的方式 改成對一個 Function 去拆分!

這樣會拆分得更細! 重用的機會也就更多!

以上大概就是我讀了下面那樣多篇的一些粗淺心得!

//==================================================

Riot.js — 1Kb 大小的 JavaScript 的 MVP 框架
http://www.oschina.net/translate/riotjs-the-1kb-mvp-framework

MVC和MVP的一些思考
http://www.cnblogs.com/janyou/archive/2008/12/05/1348244.html

Scaling Isomorphic Javascript Code
http://blog.nodejitsu.com/scaling-isomorphic-javascript-code/

[PureMVC]初學者入門教學Part.1 Application與Facde
http://www.ria.tw/2010/08/puremvcpart1-applicationfacde.html

Understanding MVC And MVP (For JavaScript And Backbone Developers)
http://addyosmani.com/blog/understanding-mvc-and-mvp-for-javascript-and-backbone-developers/

MVFM vs MVVM 的分析 比較
http://www.devdiv.com/mvfm_-blog-55433-50285.html

框架設計! 使用分析過程!
http://my.eoe.cn/961719/articles

Python里没有接口,如何写设计模式?
http://www.zhihu.com/question/20685467

充血模型与贫血模型分别适用于何种情况?
http://www.zhihu.com/question/20360521

如何区分javascript设计模式中的中介者模式(Mediator Pattern)与观察者模式(Observer Pattern)?
http://www.zhihu.com/question/21092827

MVC MVP MVVM MVFM 等的分析比較!
http://www.cnblogs.com/indream/p/3602348.html


http://seldo.com/weblog/2011/06/15/orm_is_an_antipattern

http://www.xuebuyuan.com/1230694.html

再抽象一点
http://techsingular.net/?p=1125

2014年4月26日 星期六

[JS] 嘗試 製作簡單的 視差效果!

前一段時間 很流行的 視差效果!

終於有花一小段時間 弄了一個簡單的版本!

雖然是使用別人的類別作的

不過大致的瞭解了其中的技術是怎樣做的

使用了一些 視差效果 的套件

幾乎每一款都有各自的特點!

使用方法也都不同

但是我最後決定使用的是 skrollr 這一套

因為他的使用方法簡單 和 API 相當的友善 看過 demo 後就會用 9 成

不過讓我決定使用這一套工具的原因有下面幾點

1.  API 簡單
2. 手機可以使用
3. 基本需求都可以達成
4. 到現在還有在更新
5. 說明明白扼要
6. 體積小!

經過實機測試 在我手機的瀏覽器 可以使用

和我測試的其他的 API 有所不同 !

有一些在手機上是會有問題的

測試網頁

基本上和原本的 demo 是差不多的 不過用我自己的方式詮釋一次!


參考資料:
http://stephband.info/jparallax/
http://joydesign.coletree.com/2012/07/1562/
https://github.com/Prinzhorn/skrollr
http://www.webhek.com/misc/parallax/
http://www.mrmu.com.tw/2011/10/19/parallax-scrolling/
http://webdesignledger.com/inspiration/21-examples-of-parallax-scrolling-in-web-design
http://rettamkrad.blogspot.tw/2013/05/blog-post.html

2014年4月21日 星期一

[as] 使用 Ant 編譯並測試 我自己的 unit test

繼續上一篇 我自己彷 flex unit 作的 unit test

其實還有一個需求是可以整合 Jenkins 等

可以自動的 編譯 測試  整合 發現錯誤 !

講講我遇到的幾個問題點!

1. 如何在 command line 下執行 swf ?

ans :
因為我知道有 adl, fdb 這兩樣可以 command line 測試 swf or air 的程式
為了簡單起見, 選擇使用 fdb 去測試 !
雖然我覺得使用 adl 去測試會是比較好的選項
因為 air 可以直接輸出檔案 ! 更便於報表執行 等等
不過在我心裡想 那是最後必殺技..
所以接下去的問題都將由 fdb 去做考慮.

2.  如何使用 ant 自動輸入文字讓 fdb 可以執行

ans:
其實這個問題 卡最久 ! 
不過後來看 exec task 時發現有一個 input 和 inputstring
我就利用了 inputstring 去輸入文字
不過問題在於 只能輸入一種!
如果要再輸入其他的 例如 quit , yes 等
好像沒辦法 !

3.  如何停止並關閉 fdb

ans:
這個部分 有繼續翻 task 或是 fdb 相關的部分
想說是不是有 類似的東西 可以輸入 或是 去停止的!
不過 在沒發現太多可行的方法
所以我再一次的修正了我的 BasicUnitTestCase
讓 swf 去執行 System.exit(0); 去結束 fdb

4. 如何 output 內容 ?

ans:
目前所說的 output 的部分
只是簡單的再 ant 上trace出來
還沒有整合到 Jenkins 去判斷結果的部分
之前嘗試的幾種方式 cmd, bat 等等
都會另外開啟令一個視窗 結果 ant 就結束了!
不過後來就改成直接執行 fdb 後就可以 trace 了 !


下面就是我用來測試 swf 的 基本版 task 
      <target name="open player">
            <echo>Launching '${DEPLOY_DIR}/unitTestDemo.swf'...</echo>
            <exec executable="fdb" failonerror="false" inputstring="continue"  >
                <arg line="run '${DEPLOY_DIR}/unitTestDemo.swf'" />
            </exec>
       </target>


下面是我的測試圖片!



我參考的幾篇文章
http://anycent.blog.163.com/blog/static/84498427201022335056341/
https://ant.apache.org/manual/Tasks/exec.html
http://forums.adobe.com/message/3385890#3385890#3385890

2014年4月19日 星期六

[AS] Unit Test 的基本測試工具

因為不是每個 Flash IDE 都有簡單的 flex unit 可以使用!

所以我仿照 flex unit 作了一個自己的測試類別 BasicUnitTestCase

只要繼承這個類別

就可以仿照 flex unit 4 的方式來建構 test case

並且簡單的測試!

不需要使用 premium 版本的 IDE

也不需要特定的 IDE 等等的部分!

當然也有一些別人寫好的這種類別

例如 asUnit asUnit Git URL

因為某些原因所以  asunit 對我來說不是很適用,

所以才產出了這個類別 !

來講一下我寫這個 測試類別的基本需求

1. 可以直接和 flex unit 交互使用(test case, Assert ).
2. 提供簡易報表 和 詳細報表
3. 簡單的使用和測試.

因為需求 1,

所以有了 metadata 的分析

和 flex unit 一樣直接取 Test tag 的 test case

也和 flex unit 一樣的基本斷言函式 assertEquals

為了測試正確 所以暫時不使用 flex unit 的 Before 和 After 這兩個 metadata,

強迫使用者複寫 startUp 和 shutdown 這兩個函數

確保一定會做到這兩個動作!

因為需求 2.

整個測試完畢會使用 showLog 將基本的報告印出.

也可以使用 Detail 來取的比較完整的報告

最後需求3.

只需要 BasicUnitTestCase 就可以進行測試,

雖然目前功能還是相對簡單! 

所以對目前的幾個 IDE 介面都可以使用.

綜合以上 有了下面的類別
package com.tenchiwang.unitTest
{
    import flash.events.ErrorEvent;
    import flash.utils.describeType;

    public class BasicUnitTestCase
    {
        private var _testCaseList:Vector.<TestCaseVo>;
        private var _detail:String = '';
        private var _ErrorCount:int;
        private var _PassCount :int;
        private var _isPass:Boolean = false;
        private var _callback:Function;
       
        // 基本的測試類別!
        public function BasicUnitTestCase(callBack:Function = null)
        {
            _callback = callBack;
            _testCaseList = new Vector.<TestCaseVo>();
           
            saveDetail('Analyze Unit Test....');
           
            var accessorsList:XMLList = describeType(this).method;
            var fun:Function;
            var vo:TestCaseVo;
            var acces:XML;
            var metadataName:String;
           
            for(var i:int = 0;i<accessorsList.length();i++)
            {
                acces = accessorsList[i];
                metadataName = acces.metadata[0].@name;
                metadataName = metadataName.toLocaleLowerCase();
               
                switch(metadataName)
                {
                    case 'test':
                        fun = this[acces['@name']] as Function;
                       
                        if(fun != null)
                        {
                            vo = new TestCaseVo();
                            vo.name = acces['@name'];
                            vo.fun = fun;
                             _testCaseList.push(vo);
                        }
                        break;
                   
                    default:
                }
            }
           
            saveDetail('Analyze Unit Test End. Get ' + _testCaseList.length + ' tests');
            //
            runTest();
           
            //
            if(_callback != null)
                _callback.apply();
        }
       
        final public function assertEquals(a:*, b:*):void
        {
            if( a === b)
            {
                _PassCount++;
                _isPass = true;
            }
        }
       
        private function runTest():void
        {
            showLog('Unit Test Start.');
           
            saveDetail('Unit Test Start ....');
            saveDetail('=======================');
            var len:int = _testCaseList.length;
            var vo:TestCaseVo;
            for(var i:int = 0; i < len ;i++)
            {
                vo = _testCaseList[i];
               
                saveDetail( vo.name + ' Start.' );
               
                _isPass = false;
                startUp();
               
                try
                {
                    vo.fun.call();
                }
                catch(error:Error)
                {
                    showLog('Test Case ' + vo.name + ' Error.');
                    saveDetail('Test Case ' + vo.name + ' Error.');
                    _ErrorCount++;
                }
                catch(evt:ErrorEvent)
                {
                    showLog('Test Case ' + vo.name + ' Error.');
                    saveDetail('Test Case ' + vo.name + ' Error.');
                    _ErrorCount++;
                }

                shutdown();
                saveDetail(vo.name + ' End. ' );
            }
            showLog('Unit Test End.');
           
            showLog('Test Case ' + len);
            showLog('Pass Case '  + _PassCount );
            showLog('Error Case ' + _ErrorCount);
           
           
            //
            saveDetail('=======================');
            saveDetail('Unit Test End.');
           
            saveDetail('Test Case ' + len);
            saveDetail('Pass Case '  + _PassCount );
            saveDetail('Error Case ' + _ErrorCount);
           
        }
       
        private function saveDetail(msg:String):void
        {

           
            _detail += getDate() + msg + '\n';
        }
       
        private function getDate():String
        {
            var date:Date = new Date();
            var dateStr:String = '[' + date.getUTCHours() + ' : ' + date.getUTCMinutes() + ' : ' +
                date.getUTCSeconds() + ' ' + date.getUTCMilliseconds() +'] ' ;
           
            return dateStr;
        }
       
        /**
         *  每次 unit test 前須要做的事
         */
        protected function startUp():void
        {
            throw new Error('Plz override startUp.');
        }
       
        /**
         *  每次 unit test 後須要做的事
         */
        protected function shutdown():void
        {
            throw new Error('Plz override shutdown.');
        }
       
        /**
         * 預設的顯示 Log 的通用函數
         * @param msg
         *
         */       
        protected function showLog(msg:String):void
        {
            trace(getDate() + msg);
        }
       
        /**
         * 顯示詳細的測試資料.
         */
        public function get Detail():String
        {
            return _detail;
        }
       
    }
}

internal class TestCaseVo
{
    public var name:String;
    public var fun:Function;
}

[AS] 簡易的事件機制的單元測試


上一篇 介紹了一個 簡單的事件機制類別

主要的需求是
1. 可以註冊監聽事件.
2. 可以移除單一事件
3. 可以移除全部的事件
4. 可以傳遞參數
5. 不同於 flash 基本的事件機制.

下面我基於這幾個需求寫了一些單元測試!

1. 可以註冊監聽事件.

        [Test]
        public function testSendEvent():void
        {
            EventManager.getInstancet().addListener(TEST_SEND_EVENT, _mock.handler);
            EventManager.getInstancet().sendEvent(TEST_SEND_EVENT);
            assertEquals(_isGetEvent, true);
        }


2. 可以移除單一事件
        [Test]
        public function testRemoveEvent():void
        {
            EventManager.getInstancet().addListener(TEST_REMOVE_EVENT, _mock.handler);
            EventManager.getInstancet().removeListener(TEST_REMOVE_EVENT, _mock.handler);
            EventManager.getInstancet().sendEvent(TEST_REMOVE_EVENT);
            assertEquals(_isGetEvent, false);
        }


3. 可以移除全部的事件
        [test]
        public function testRemoveEventAllListener():void
        {
            var EVENT_ONE:String = 'EVENT_ONE';
            var EVENT_TWO:String = 'EVENT_TWO';
           
            _mock.eventOneCount = 0;
            _mock.eventOnTwoCount = 0;
           
            _mock.handlerEvent1 = function():void
            {
                _mock.eventOneCount++;
            };
            _mock.handlerEvent2 = function():void
            {
                _mock.eventOneCount++;
            };
            _mock.handlerEvent3 = function():void
            {
                _mock.eventOneCount++;
            };
            _mock.handlerEvent4 = function():void
            {
                _mock.eventOnTwoCount++;
            };
           
            EventManager.getInstancet().addListener(EVENT_ONE, _mock.handlerEvent1);
            EventManager.getInstancet().addListener(EVENT_ONE, _mock.handlerEvent2);
            EventManager.getInstancet().addListener(EVENT_ONE, _mock.handlerEvent3);
            EventManager.getInstancet().addListener(EVENT_ONE, _mock.handlerEvent4);
           
            EventManager.getInstancet().addListener(EVENT_TWO, _mock.handlerEvent4);
           
            EventManager.getInstancet().removeListenerAll(EVENT_ONE);
           
            EventManager.getInstancet().sendEvent(EVENT_ONE);
            EventManager.getInstancet().sendEvent(EVENT_TWO);
           
            if(_mock.eventOneCount == 0 && _mock.eventOnTwoCount == 1)
                assertEquals(true, true);
        }


4.可以傳遞參數
        [test]
        public function testSendParmas():void
           
        {
            EventManager.getInstancet().addListener(TEST_PARAMS_EVENT, _mock.handlerParams);
            EventManager.getInstancet().sendEvent(TEST_PARAMS_EVENT, TEST_MSG, TEST_MSG2);
        }


5. 不同於 flash 基本的事件機制.
EventManager.getInstancet().addListener(eventType:String, handler:Function);
EventManager.getInstancet().sendEvent(eventType:String, ...args);


所以主要的需求都有相關的 test case,

然後針對一些這個類別使用上的問題,

也都有相關的 test case 讓使用者可以了解一些使用的限制,

像是可以註冊兩個一樣事件 一樣監聽函數

發送一次事件可以執行兩次! 移除時也只會移除一個

監聽事件的執行的位置! 傳送的參數有差別時會出現那些錯誤!

監聽函數的執行順序, 傳入空監聽的情況,

各種使用上的特殊情況, 正常情況都記錄起來

未來有需求在修改這個類別後

可以在進行一次這些測試! 

用來證明以前的需求, 在修改後不會產生錯誤!

下面是全的 test case 的 code
package
{
    import com.tenchiwang.manager.EventManager;
    import com.tenchiwang.unitTest.BasicUnitTestCase;
   
    public class demo3 extends BasicUnitTestCase
    {
       
        private var _isGetEvent:Boolean = false;
        private var _mock:Object;
       
        private const TEST_SEND_EVENT:String      = 'TEST_SEND_EVENT';
        private const TEST_REMOVE_EVENT:String    = 'TEST_REMOVE_EVENT';
        private const TEST_PARAM_EVENT:String     = 'TEST_PARAM_EVENT';
        private const TEST_PARAMS_EVENT:String    = 'TEST_PARAMS_EVENT';
        private const TEST_CURRENT_REMOVE:String  = 'TEST_CURRENT_REMOVE';
        private const TEST_ORDER_EVENT:String     = 'TEST_ORDER_EVENT';
       
        private const TEST_MSG:String  = 'TEST_MSG';
        private const TEST_MSG2:String = 'TEST_MSG2';
       
        //============== 正常案例   && 邊界案例
        [Test]
        public function testSendEvent():void
        {
            EventManager.getInstancet().addListener(TEST_SEND_EVENT, _mock.handler);
            EventManager.getInstancet().sendEvent(TEST_SEND_EVENT);
            assertEquals(_isGetEvent, true);
        }
       
        [Test]
        public function testRemoveEvent():void
        {
            EventManager.getInstancet().addListener(TEST_REMOVE_EVENT, _mock.handler);
            EventManager.getInstancet().removeListener(TEST_REMOVE_EVENT, _mock.handler);
            EventManager.getInstancet().sendEvent(TEST_REMOVE_EVENT);
            assertEquals(_isGetEvent, false);
        }
       
        [test]
        public function testSendParma():void
        {
            EventManager.getInstancet().addListener(TEST_PARAM_EVENT, _mock.handlerParam);
            EventManager.getInstancet().sendEvent(TEST_PARAM_EVENT, TEST_MSG);
        }
       
        [test]
        public function testSendParmas():void
           
        {
            EventManager.getInstancet().addListener(TEST_PARAMS_EVENT, _mock.handlerParams);
            EventManager.getInstancet().sendEvent(TEST_PARAMS_EVENT, TEST_MSG, TEST_MSG2);
        }
       
        [test]
        public function testCurrentRemove():void
        {
            EventManager.getInstancet().addListener(TEST_CURRENT_REMOVE, _mock.handlerCurrent);
            EventManager.getInstancet().addListener(TEST_CURRENT_REMOVE, _mock.handlerRemoveCurrent);
           
            EventManager.getInstancet().removeListener(TEST_CURRENT_REMOVE, _mock.handlerRemoveCurrent);
           
            EventManager.getInstancet().sendEvent(TEST_CURRENT_REMOVE);
           
            assertEquals(_isGetEvent, true);
        }
       
        [test]
        public function testCurrentRemove2():void
        {
            _mock.handlerCurrent = function():void
            {
                _isGetEvent  = false;
            }
           
            _mock.handlerRemoveCurrent = function():void
            {
                _isGetEvent = true;
            }
           
            EventManager.getInstancet().addListener(TEST_CURRENT_REMOVE, _mock.handlerCurrent);
            EventManager.getInstancet().addListener(TEST_CURRENT_REMOVE, _mock.handlerRemoveCurrent);
           
            EventManager.getInstancet().removeListener(TEST_CURRENT_REMOVE, _mock.handlerCurrent);
           
            EventManager.getInstancet().sendEvent(TEST_CURRENT_REMOVE);
           
            assertEquals(_isGetEvent, true);
        }
       
        [test]
        public function testOrder():void
        {
            _mock.order = 0;
            _mock.handlerOrder1 = function():void
            {
                if(_mock.order == 0)
                    _mock.order = 1;
            };
               
            _mock.handlerOrder2 = function():void
            {
                if(_mock.order == 1)
                    _mock.order = 2;
            };
           
            EventManager.getInstancet().addListener(TEST_ORDER_EVENT, _mock.handlerOrder1);
            EventManager.getInstancet().addListener(TEST_ORDER_EVENT, _mock.handlerOrder2);
           
            EventManager.getInstancet().sendEvent(TEST_ORDER_EVENT);
           
            assertEquals(_mock.order, 2);
        }
       
        [test]
        public function testDouble():void
        {
            var TEST_DOUBLE_EVENT:String = 'TEST_DOUBLE_EVENT';
           
            _mock.count = 0;
            _mock.handlerDouble = function():void
            {
                _mock.count++;
            };
           
           
            EventManager.getInstancet().addListener(TEST_DOUBLE_EVENT, _mock.handlerDouble);
            EventManager.getInstancet().addListener(TEST_DOUBLE_EVENT, _mock.handlerDouble);
           
            EventManager.getInstancet().sendEvent(TEST_DOUBLE_EVENT);
           
            assertEquals(_mock.count, 2);
        }
       
        [test]
        public function testRemoveDouble():void
        {
            var TEST_REMOVE_DOUBLE_EVENT:String = 'TEST_REMOVE_DOUBLE_EVENT';
           
            _mock.count = 0;
            _mock.handlerDouble = function():void
            {
                _mock.count++;
            };
           
            EventManager.getInstancet().addListener(TEST_REMOVE_DOUBLE_EVENT, _mock.handlerDouble);
            EventManager.getInstancet().addListener(TEST_REMOVE_DOUBLE_EVENT, _mock.handlerDouble);
           
            EventManager.getInstancet().removeListener(TEST_REMOVE_DOUBLE_EVENT, _mock.handlerDouble);
           
            EventManager.getInstancet().sendEvent(TEST_REMOVE_DOUBLE_EVENT);
           
            assertEquals(_mock.count, 1);
        }
       
        [test]
        public function testRemoveEventAllListener():void
        {
            var EVENT_ONE:String = 'EVENT_ONE';
            var EVENT_TWO:String = 'EVENT_TWO';
           
            _mock.eventOneCount = 0;
            _mock.eventOnTwoCount = 0;
           
            _mock.handlerEvent1 = function():void
            {
                _mock.eventOneCount++;
            };
            _mock.handlerEvent2 = function():void
            {
                _mock.eventOneCount++;
            };
            _mock.handlerEvent3 = function():void
            {
                _mock.eventOneCount++;
            };
            _mock.handlerEvent4 = function():void
            {
                _mock.eventOnTwoCount++;
            };
           
            EventManager.getInstancet().addListener(EVENT_ONE, _mock.handlerEvent1);
            EventManager.getInstancet().addListener(EVENT_ONE, _mock.handlerEvent2);
            EventManager.getInstancet().addListener(EVENT_ONE, _mock.handlerEvent3);
            EventManager.getInstancet().addListener(EVENT_ONE, _mock.handlerEvent4);
           
            EventManager.getInstancet().addListener(EVENT_TWO, _mock.handlerEvent4);
           
            EventManager.getInstancet().removeListenerAll(EVENT_ONE);
           
            EventManager.getInstancet().sendEvent(EVENT_ONE);
            EventManager.getInstancet().sendEvent(EVENT_TWO);
           
            if(_mock.eventOneCount == 0 && _mock.eventOnTwoCount == 1)
                assertEquals(true, true);
        }
       
        //================ 錯誤案例!
        [test]
        public function testMoreParamError():void
        {
            var TEST_MORE_PARAMS:String = 'TEST_MORE_PARAMS';
           
            _mock.count = 0;
            _mock.handler2 = function(msg:String):void
            {
                if(msg == TEST_MSG)
                    _mock.count++;
            };
           
            EventManager.getInstancet().addListener(TEST_MORE_PARAMS, _mock.handler2);
            try
            {
                EventManager.getInstancet().sendEvent(TEST_MORE_PARAMS, TEST_MSG, TEST_MSG2);               
            }
            catch(error:Error)
            {
                assertEquals(_mock.count, 0);
            }
           
        }
       
        [test]
        public function testlessParamError():void
        {
            var TEST_LESS_PARAMS:String = 'TEST_LESS_PARAMS';
           
            _mock.count = 0;
            _mock.handler2 = function(msg:String, msg2:String):void
            {
                _mock.count++;
            };
           
            EventManager.getInstancet().addListener(TEST_LESS_PARAMS, _mock.handler2);
            try
            {
                EventManager.getInstancet().sendEvent(TEST_LESS_PARAMS, TEST_MSG);               
            }
            catch(error:Error)
            {
                assertEquals(_mock.count, 0);
            }
           
        }
       
        //================ 特殊案例
       
        [test]
        public function testFunctionLocal():void
        {
            var TEST_LOCAL:String = 'TEST_LOCAL';
           
            _mock.handler = function(msg:String):void
            {
                if(this == EventManager.getInstancet())
                    assertEquals(true, true);
            };
           
            EventManager.getInstancet().addListener(TEST_LOCAL, _mock.handler);
            EventManager.getInstancet().sendEvent(TEST_LOCAL, TEST_MSG);               
           
        }
       
        [test]
        public function testMoreParam():void
        {
            var TEST_MORE_PARAM:String = 'TEST_MORE_PARAM';
            var TEST_MORE_PARAMS:String = 'TEST_MORE_PARAMS';
           
            _mock.count = 0;
            _mock.handler = function():void
            {
                _mock.count++;
            };
               
            EventManager.getInstancet().addListener(TEST_MORE_PARAM, _mock.handler);
            EventManager.getInstancet().addListener(TEST_MORE_PARAMS, _mock.handler);
           
            EventManager.getInstancet().sendEvent(TEST_MORE_PARAM, TEST_MSG);
            EventManager.getInstancet().sendEvent(TEST_MORE_PARAMS, TEST_MSG, TEST_MSG2);
           
            assertEquals(_mock.count, 2);
        }
       
        [test]
        public function testNullHandler():void
        {
           
            var TEST_FUNCTION_NULL:String = 'TEST_FUNCTION_NULL';
            _mock.count = 0;
            _mock.handler = function(msg:String):void
            {
                if(msg == TEST_MSG)
                    _mock.count++;
            };
           
            EventManager.getInstancet().addListener(TEST_FUNCTION_NULL, _mock.handler);
           
            _mock.handler = null;
           
            EventManager.getInstancet().sendEvent(TEST_FUNCTION_NULL, TEST_MSG);   
           
            assertEquals(_mock.count, 1);
        }

        [test]
        public function testNullObject():void
        {
           
            var TEST_OBJECT_NULL:String = 'TEST_OBJECT_NULL';
            _mock.handler = function(msg:String):void
            {
                _isGetEvent = true;
            };
           
            EventManager.getInstancet().addListener(TEST_OBJECT_NULL, _mock.handler);
           
            _mock = null;
           
            EventManager.getInstancet().sendEvent(TEST_OBJECT_NULL, TEST_MSG);                   
            assertEquals(_isGetEvent, true);
           
        }       
       
        //================
       
        override protected function startUp():void
        {
            _isGetEvent = false;
           
            _mock = new Object();
            _mock.handler = function():void
            {
                _isGetEvent = true;
            };
           
            _mock.handlerParam = function(msg:String):void
            {
                assertEquals(msg, TEST_MSG);
            };
               
            _mock.handlerParams = function(msg:String, msg2:String):void
            {
                var flag:Boolean  = (msg == TEST_MSG);
                var flag2:Boolean = (msg2 == TEST_MSG2);
               
                if(flag && flag2)
                    assertEquals(true, true);
            };
           
            _mock.handlerCurrent = function():void
            {
                _isGetEvent  = true;
            }
           
            _mock.handlerRemoveCurrent = function():void
            {
                _isGetEvent = false;
            }
        }
       
        override protected function shutdown():void
        {
            _mock = null;
            EventManager.getInstancet().clearAll();
        }
    }
}


使用自製的 Unit Test , 執行測試並且顯示的網頁.

[AS] 簡易的事件機制


因為開始製作  "樣板" !

為了區隔 "樣板內" 和 "樣板外" 的事件, 流程

讓兩種事件不能互相溝通,

甚至機制也不一樣來避免被攔截 監聽 等等等

讓 "樣板外" 的部分 不能輕易利用機制外的改變  "樣板內" 流程 !

所以我仿照 pureMVC 的事件機制,

製作了一個簡易的事件類別 !

主要的需求是
1. 可以註冊監聽事件.
2. 可以移除單一事件
3. 可以移除全部的事件
4. 可以傳遞參數
5. 不同於 flash 基本的事件機制.


下面是 這個 事件類別 的 code
package com.tenchiwang.manager
{

    public final class EventManager
    {
        static private var _instance:EventManager;
       
        static public function getInstancet():EventManager
        {
            if(!_instance)
                _instance = new EventManager(new SingletonEnforcer());
            return _instance;
        }
       
        public function EventManager(sc:SingletonEnforcer){}
       
        private var eventList:Object = new Object();
       
        public function addListener(eventType:String, handler:Function):int
        {
            if(eventList[eventType] == undefined)
                eventList[eventType] = new Vector.<Function>();
           
            var vec:Vector.<Function> = eventList[eventType] as Vector.<Function>;
            vec.push(handler);
           
            return vec.length;
        }
       
        public function sendEvent(eventType:String, ...args):void
        {
            if(eventList[eventType] == undefined)
                return;
           
            var vec:Vector.<Function> = eventList[eventType] as Vector.<Function>;
            var len:int = vec.length;
           
            for(var i:int = 0; i < len; i++)
            {
                if(vec[i] != null)
                    vec[i].apply(this, args);
            }
        }
       
        public function removeListener(eventType:String, handler:Function):void
        {
            if(eventList[eventType] == undefined)
                return;
           
            var vec:Vector.<Function> = eventList[eventType] as Vector.<Function>;
            var len:int = vec.length;
           
            for(var i:int = 0; i < len; i++)
            {
                if(vec[i] === handler)
                {
                    vec[i] = null;
                    return;
                }
            }
        }
       
        public function removeListenerAll(eventType:String):void
        {
            if(eventList[eventType] == undefined)
                return;
           
            var vec:Vector.<Function> = eventList[eventType] as Vector.<Function>;
            var len:int = vec.length;
           
            for(var i:int = 0; i < len; i++)
            {
                    vec[i] = null;
            }
           
            vec = null;
           
            delete eventList[eventType];
        }
       
        public function clearAll():void
        {
            for(var key:String in eventList)
                removeListenerAll(key);
        }
       
    }
}
internal class SingletonEnforcer{}



然後為了確認這個 "事件類別" 是可以正常並且如估計運行, 

所以我寫了一些的單元測試!

下一篇, 將介紹我寫了那些單元測試, 來測試這個單元