<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經轉移至github,大家請訪問 http://qaseven.github.io/

    Python簡單速度測試

     剛開始接觸python,對其飄逸的語法所“震撼”,與其說是在寫代碼,還不如說是在說一段代碼。
      剛開始學吧,寫個簡單的程序練一下手吧,就寫了一個歸并排序的算法
    def merge(num_list,l_b,l_e,r_b,r_e):
    temp=[]
    begin=l_b
    while l_b<=l_e and r_b<=r_e:
    if num_list[l_b] < num_list[r_b]:
    temp.append(num_list[l_b])
    l_b=l_b+1
    else:
    temp.append(num_list[r_b])
    r_b=r_b+1
    while l_b<=l_e:
    temp.append(num_list[l_b])
    l_b=l_b+1
    while r_b<=r_e:
    temp.append(num_list[r_b])
    r_b=r_b+1
    for index in range(0,len(temp)):
    num_list[begin+index]=temp[index]
    def mergeSort(num_list,b,e):
    if b<e:
    mid=int((b+e)/2)
    mergeSort(num_list,b,mid)
    mergeSort(num_list,mid+1,e)
    l_b=b
    l_e=mid
    r_b=mid+1
    r_e=e
    merge(num_list,l_b,l_e,r_b,r_e)
    def main():
    num_list=[5,4,1,7,9,8,6,5,4,7]
    mergeSort(num_list)
    if __name__=="__main__":
    main()
     寫完感覺還不錯,于是乎上網看看別人用python咋寫的。果然出乎我的預料,我仿造其格式,寫了一下
    def mergeSort(num_list):
    if len(num_list)<=1: return num_list
    mid=int(len(num_list)/2)
    return merge(mergeSort(num_list[:mid]),mergeSort(num_list[mid:]))
    def merge(l_list,r_list):
    temp_list=[]
    while l_list and r_list:
    temp_list.append(l_list.pop(0)) if l_list[0]<=r_list[0] else temp_list.append(r_list.pop(0))
    return temp_list+l_list+r_list
      短小精悍,剛開始我懷疑 這么寫的效率有沒有問題啊。因為我原來的算法在函數之間不用傳參數,就簡單測試一下,再次出乎的預料,通過跑10w次,我原來的算法接近5s,而這個算法不到4秒,好吧,以后還是要使用python的思維寫python代碼,不過真的很優雅。

    posted @ 2014-06-04 10:57 順其自然EVO 閱讀(303) | 評論 (0)編輯 收藏

    識別訪問端的操作系統

    //識別訪問端的操作系統
    function PDD() {
    //平臺、設備和操作系統
    var system = {
    win: false,
    mac: false,
    xll: false
    };
    //檢測平臺
    var p = navigator.platform;
    system.win = p.indexOf("Win") == 0;
    system.mac = p.indexOf("Mac") == 0;
    system.x11 = (p == "X11") || (p.indexOf("Linux") == 0);
    //跳轉語句
    alert(p);
    if (system.win) {
    alert("win");
    } else if (system.mac) {
    alert("mac");
    } else if (system.x11) {
    alert("X11 Or Linux");
    } else {
    alert("android");
    }
    if (system.win || system.mac || system.xll) {
    } else {
    window.location.href = "android.aspx";
    }
    }

    posted @ 2014-06-04 10:50 順其自然EVO 閱讀(183) | 評論 (0)編輯 收藏

    測試之路1—熟悉使用Junit

     測試有很多種,不僅僅是手動測試,往往還要用到所謂“自動化測試”,其實我的理解也就是自己寫個程序去測試。
      最近在公司實習,用到自動化測試,因為程序都是用java編寫的,所以我也用java編寫單元測試程序。一般都在java中已經導入junit
      import junit.framework.TestCase;
      但是我看老大給我的例程都沒與引入這個類,而是引入了
    <pre name="code" class="java">import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import static org.junit.Assert.*;
      然后,老大叫我根據他給的例程自己去創建單元測試程序,然后運行,創建實際的任務。
      創建任務,看似不是很難,但仍要花點時間去了解Junit是怎么樣的,所以我需要先了解一下。
      首先這也是一個類,和其他java的類一樣,無非引入了Junit的類,然后我就發現了這個類并沒有顯式的寫出自己的構造方法,而是只有一些看似比較常見對于字符串操作的方法。
      唯一不同的是它在每一個方法前都有一個注解。就和前面import的東西一樣,有@after,@Before,@Test。
      那么這些注解就是單元測試的關鍵了:
      你要在方法的前面使用 @Test標注,以表明這是一個測試方法;用@Before來標注它“在任何一個測試執行之前必須執行的代碼 ;在這種測試函數的前面加上@Ignore 標注,這個標注的含義就是 “ 某些方法尚未完成,暫不參與此次測試;
      那么最最簡單實現單元測試花其實只要做兩步就可以測試程序了:初始化,測試。而測試的代碼放在@Test標注的方法內即可。如圖所示,就是一段單元測試的代碼:
    public void creatAAC_Task() throws DocumentException {
    //      String[] sampleratelist = { "24000", "32000", "44100", "48000" };
    String[] sampleratelist = { "24000" };
    for (int j = 0; j < sampleratelist.length; j++) {
    TaskPara model = new TaskPara();
    model.setTaskName("AAC_" + sampleratelist[j]);
    //model.setVideoCodec("h264");
    model.setVideoProfile("Main");
    model.setAudioCodec("aac");
    //model.setAudioProfile("LC");
    model.setSamplerate(sampleratelist[j]);
    String content = taskcaseAPIs.createTaskXML(model);
    String xmlString = arcvideo.addNewTask(content);
    assertTrue(!xmlString.contains("<errors>"));
    //compare(e://xml2.xml);
    String taskID = taskAPIs.getTaskID(xmlString);
    String delXML = arcvideo.deleteTask(taskID);
    assertTrue(delXML.contains("<success></success>"));
    }
    }
      而運行這個方法也不需要直接用main函數作為入口地址,只需要選擇該方法,點擊右鍵Run as->Junit test 或Debug as->Junit test。即可運行該單元測試方法,運行的結果是直接在服務器上創建一個任務,如下圖所示:
      那么任務就已經被創建好了。而任務的名稱就是方法里輸出任務的字符串。
      這就是一個簡單的單元測試。

    posted @ 2014-06-04 10:50 順其自然EVO 閱讀(205) | 評論 (0)編輯 收藏

    SQL Server 監控統計阻塞腳本信息

    數據庫產生阻塞(Blocking)的本質原因 :SQL語句連續持有鎖的時間過長 ,數目過多, 粒度過大。阻塞是事務隔離帶來的副作用,它是不可避免的,而且是一個數據庫系統常見的現象。 但是阻塞的時間和出現頻率要控制在一定的范圍內,阻塞持續的時間過長或阻塞出現過多(過于頻繁),就會對數據庫性能產生嚴重的影響。
      很多時候,DBA需要知道數據庫在出現性能問題時,有沒有發生阻塞? 什么時候開始的?發生在那個數據庫上? 阻塞發生在那些SQL語句之間? 阻塞的時間有多長? 阻塞發生的頻率? 阻塞有關的連接是從那些客戶端應用發送來的?.......
      如果我們能夠知道這些具體信息,我們就能迅速定位問題,分析阻塞產生的原因,  從而找出出現性能問題的根本原因,并根據具體原因給出相應的解決方案(索引調整、優化SQL語句等)。
      查看阻塞的方法比較多, 我在這篇博客MS SQL 日常維護管理常用腳本(二)里面提到查看阻塞的一些方法:
      方法1:查看那個引起阻塞,查看blk不為0的記錄,如果存在阻塞進程,則是該阻塞進程的會話 ID。否則該列為零。
      EXEC sp_who active
      方法2:查看那個引起阻塞,查看字段BlkBy,這個能夠得到比sp_who更多的信息。
      EXEC sp_who2 active
      方法3:sp_lock 系統存儲過程,報告有關鎖的信息,但是不方便定位問題
      方法4:sp_who_lock存儲過程
      方法5:右鍵服務器-選擇“活動和監視器”,查看進程選項。注意“任務狀態”字段。
      方法6:右鍵服務名稱-選擇報表-標準報表-活動-所有正在阻塞的事務。
      但是上面方法,例如像sp_who、 sp_who2,sp_who_lock等,都有或多或少的缺點:例如不能查看阻塞和被阻塞的SQL語句。不能從查看一段時間內阻塞發生的情況等;沒有顯示阻塞的時間....... 我們要實現下面功能:
      1:  查看那個會話阻塞了那個會話
      2:阻塞會話和被阻塞會話正在執行的SQL語句
      3:被阻塞了多長時間
      4:像客戶端IP、Proagram_Name之類信息
      5:阻塞發生的時間點
      6:阻塞發生的頻率
      7:如果需要,應該通知相關開發人員,DBA不能啥事情都包攬是吧,那不還得累死,總得讓開發人員員參與進來優化(有些問題就該他們解決),多了解一些系統運行的具體情況,有利于他們認識問題、解決問題。
      8:需要的時候開啟這項功能,不需要關閉這項功能
      于是為了滿足上述功能,有了下面SQL 語句
    SELECT wt.blocking_session_id                  AS BlockingSessesionId
    ,sp.program_name                         AS ProgramName
    ,COALESCE(sp.LOGINAME, sp.nt_username)   AS HostName
    ,ec1.client_net_address                  AS ClientIpAddress
    ,db.name                                 AS DatabaseName
    ,wt.wait_type                            AS WaitType
    ,ec1.connect_time                        AS BlockingStartTime
    ,wt.WAIT_DURATION_MS/1000                AS WaitDuration
    ,ec1.session_id                          AS BlockedSessionId
    ,h1.TEXT                                 AS BlockedSQLText
    ,h2.TEXT                                 AS BlockingSQLText
    FROM sys.dm_tran_locks AS tl
    INNER JOIN sys.databases db
    ON db.database_id = tl.resource_database_id
    INNER JOIN sys.dm_os_waiting_tasks AS wt
    ON tl.lock_owner_address = wt.resource_address
    INNER JOIN sys.dm_exec_connections ec1
    ON ec1.session_id = tl.request_session_id
    INNER JOIN sys.dm_exec_connections ec2
    ON ec2.session_id = wt.blocking_session_id
    LEFT OUTER JOIN master.dbo.sysprocesses sp
    ON SP.spid = wt.blocking_session_id
    CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
    CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
     我們做一個測試例子來驗證一下
      1:打開第一會話窗口1,執行下面語句
    USE DBMonitor;
    GO
    BEGIN TRANSACTION
    SELECT * FROM dbo.TEST(TABLOCKX);
    --COMMIT TRANSACTION;
      2:打開第二個會話窗口2,執行下面語句
      USE DBMonitor;
      GO
      SELECT * FROM dbo.TEST
      3:打開第三個會話窗口3,執行下面語句
    SELECT wt.blocking_session_id                  AS BlockingSessesionId
    ,sp.program_name                         AS ProgramName
    ,COALESCE(sp.LOGINAME, sp.nt_username)   AS HostName
    ,ec1.client_net_address                  AS ClientIpAddress
    ,db.name                                 AS DatabaseName
    ,wt.wait_type                            AS WaitType
    ,ec1.connect_time                        AS BlockingStartTime
    ,wt.WAIT_DURATION_MS/1000                AS WaitDuration
    ,ec1.session_id                          AS BlockedSessionId
    ,h1.TEXT                                 AS BlockedSQLText
    ,h2.TEXT                                 AS BlockingSQLText
    FROM sys.dm_tran_locks AS tl
    INNER JOIN sys.databases db
    ON db.database_id = tl.resource_database_id
    INNER JOIN sys.dm_os_waiting_tasks AS wt
    ON tl.lock_owner_address = wt.resource_address
    INNER JOIN sys.dm_exec_connections ec1
    ON ec1.session_id = tl.request_session_id
    INNER JOIN sys.dm_exec_connections ec2
    ON ec2.session_id = wt.blocking_session_id
    LEFT OUTER JOIN master.dbo.sysprocesses sp
    ON SP.spid = wt.blocking_session_id
    CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
    CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
      如下圖所,我們可以看到阻塞其它會話以及被阻塞會話的信息,如下所示
      現在上面SQL已經基本實現了查看阻塞具體信息的功能,但是現在又有幾個問題:
      1:上面SQL腳本只適合已經出現阻塞情況下查看阻塞信息,如果沒有出現阻塞情況,我總不能傻傻的一直在哪里點擊執行吧,因為阻塞這種情況有可能在那段時間都不會出現,只會在特定的時間段出現。
      2:我想了解一段時間內數據庫出現的阻塞情況,那么需要將阻塞信息保留下來。
      3:有時候忙不過來,我想將這些具體阻塞信息發送給相關開發人員,讓他們了解具體情況。
      于是我想通過一個存儲過程來實現這方面功能,通過設置參數@OutType,默認為輸出阻塞會話信息,當參數為"Table" 時,將阻塞信息寫入數據庫表,如果參數為 "Email"表示將阻塞信息通過郵件發送開發人員。
      正好這段時間,我在YourSQLDba上擴展一些功能,于是我將這個存儲過程放置在YouSQLDba數據庫中。
    USE [YourSQLDba]
    GO
    IF NOT EXISTS(SELECT * FROM sys.objects WHERE object_id=OBJECT_ID(N'[Maint].[BlockingSQLHistory]') AND type='U')
    BEGIN
    CREATE TABLE Maint.BlockingSQLHistory
    (
    RecordTime                        DATETIME           ,
    DatabaseName                      SYSNAME            ,
    BlockingSessesionId               SMALLINT           ,
    ProgramName                       NCHAR(128)         ,
    UserName                          NCHAR(256)         ,
    ClientIpAddress                   VARCHAR(48)        ,
    WaitType                          NCHAR(60)          ,
    BlockingStartTime                 DATETIME           ,
    WaitDuration                      BIGINT             ,
    BlockedSessionId                  INT                ,
    BlockedSQLText                    NVARCHAR(MAX)      ,
    BlockingSQLText                   NVARCHAR(MAX)      ,
    CONSTRAINT PK_BlockingSQLHistory  PRIMARY KEY(RecordTime)
    )
    END
    GO
      存儲過程如下所示:
    USE [YourSQLDba]
    GO
    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Maint].[sp_who_blocking]') AND type in (N'P', N'PC'))
    DROP PROCEDURE [Maint].[sp_who_blocking]
    GO
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    --==================================================================================================================
    --        ProcedureName         :            [Maint].[sp_who_blocking]
    --        Author                :            Kerry    http://www.cnblogs.com/kerrycode/
    --        CreateDate            :            2014-04-23
    --        Description           :            監控數據庫阻塞情況,顯示阻塞會話信息或收集阻塞會話信息或發送告警郵件
    /******************************************************************************************************************
    Parameters                   :                                    參數說明
    ********************************************************************************************************************
    @OutType         :            默認為輸出阻塞會話信息,"Table", "Email"分別表示將阻塞信息寫入表或郵件發送
    @EmailSubject    :            郵件主題.默認為Sql Blocking Alert,一般指定,例如“ServerName Sql Blocking Alert"
    @ProfileName     :            @profile_name 默認值為YourSQLDba_EmailProfile
    @RecipientsLst   :            收件人列表
    ********************************************************************************************************************
    Modified Date    Modified User     Version                 Modified Reason
    ********************************************************************************************************************
    2014-04-23             Kerry         V01.00.00         新建存儲過程[Maint].[sp_who_blocking]
    *******************************************************************************************************************/
    --==================================================================================================================
    CREATE PROCEDURE [Maint].[sp_who_blocking]
    (
    @OutType
    VARCHAR(8) ='Default'                  ,
    @EmailSubject
    VARCHAR(120)='Sql Blocking Alert'      ,
    @ProfileName
    sysname='YourSQLDba_EmailProfile'      ,
    @RecipientsLst
    VARCHAR(MAX) = NULL
    )
    AS
    BEGIN
    SET NOCOUNT ON;
    DECLARE @HtmlContent  NVARCHAR(MAX) ;
    IF @OutType NOT IN ('Default', 'Table','Email')
    BEGIN
    PRINT 'The parameter @OutType is not correct,please check it';
    return;
    END
    IF @OutType ='Default'
    BEGIN
    SELECT db.name                                 AS DatabaseName
    ,wt.blocking_session_id                  AS BlockingSessesionId
    ,sp.program_name                         AS ProgramName
    ,COALESCE(sp.LOGINAME, sp.nt_username)   AS UserName
    ,ec1.client_net_address                  AS ClientIpAddress
    ,wt.wait_type                            AS WaitType
    ,ec1.connect_time                        AS BlockingStartTime
    ,wt.WAIT_DURATION_MS/1000                AS WaitDuration
    ,ec1.session_id                          AS BlockedSessionId
    ,h1.TEXT                                 AS BlockedSQLText
    ,h2.TEXT                                 AS BlockingSQLText
    FROM sys.dm_tran_locks AS tl
    INNER JOIN sys.databases db
    ON db.database_id = tl.resource_database_id
    INNER JOIN sys.dm_os_waiting_tasks AS wt
    ON tl.lock_owner_address = wt.resource_address
    INNER JOIN sys.dm_exec_connections ec1
    ON ec1.session_id = tl.request_session_id
    INNER JOIN sys.dm_exec_connections ec2
    ON ec2.session_id = wt.blocking_session_id
    LEFT OUTER JOIN master.dbo.sysprocesses sp
    ON SP.spid = wt.blocking_session_id
    CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
    CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2;
    END
    ELSE IF @OutType='Table'
    BEGIN
    INSERT INTO [Maint].[BlockingSQLHistory]
    SELECT GETDATE()                               AS RecordTime
    ,db.name                                 AS DatabaseName
    ,wt.blocking_session_id                  AS BlockingSessesionId
    ,sp.program_name                         AS ProgramName
    ,COALESCE(sp.LOGINAME, sp.nt_username)   AS UserName
    ,ec1.client_net_address                  AS ClientIpAddress
    ,wt.wait_type                            AS WaitType
    ,ec1.connect_time                        AS BlockingStartTime
    ,wt.WAIT_DURATION_MS/1000                AS WaitDuration
    ,ec1.session_id                          AS BlockedSessionId
    ,h1.TEXT                                 AS BlockedSQLText
    ,h2.TEXT                                 AS BlockingSQLText
    FROM sys.dm_tran_locks AS tl
    INNER JOIN sys.databases db
    ON db.database_id = tl.resource_database_id
    INNER JOIN sys.dm_os_waiting_tasks AS wt
    ON tl.lock_owner_address = wt.resource_address
    INNER JOIN sys.dm_exec_connections ec1
    ON ec1.session_id = tl.request_session_id
    INNER JOIN sys.dm_exec_connections ec2
    ON ec2.session_id = wt.blocking_session_id
    LEFT OUTER JOIN master.dbo.sysprocesses sp
    ON SP.spid = wt.blocking_session_id
    CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
    CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2;
    END
    ELSE IF @OutType='Email'
    BEGIN
    SET @HtmlContent =
    N'<head>'
    + N'<style type="text/css">h2, body {font-family: Arial, verdana;} table{font-size:11px; border-collapse:collapse;} td{background-color:#F1F1F1; border:1px solid black; padding:3px;} th{background-color:#99CCFF;}</style>'
    + N'<table border="1">'
    + N'<tr>
    <th>DatabaseName</th>
    <th>BlockingSessesionId</th>
    <th>ProgramName</th>
    <th>UserName</th>
    <th>ClientIpAddress</th>
    <th>WaitType</th>
    <th>BlockingStartTime</th>
    <th>WaitDuration</th>
    <th>BlockedSessionId</th>
    <th>BlockedSQLText</th>
    <th>BlockingSQLText</th>
    </tr>' +
    CAST (
    (SELECT db.name                                  AS TD, ''
    ,wt.blocking_session_id                   AS TD, ''
    ,sp.program_name                          AS TD, ''
    ,COALESCE(sp.LOGINAME, sp.nt_username)    AS TD, ''
    ,ec1.client_net_address                   AS TD, ''
    ,wt.wait_type                             AS TD, ''
    ,ec1.connect_time                         AS TD, ''
    ,wt.WAIT_DURATION_MS/1000                 AS TD, ''
    ,ec1.session_id                           AS TD, ''
    ,h1.TEXT                                  AS TD, ''
    ,h2.TEXT                                  AS TD, ''
    FROM sys.dm_tran_locks AS tl
    INNER JOIN sys.databases db
    ON db.database_id = tl.resource_database_id
    INNER JOIN sys.dm_os_waiting_tasks AS wt
    ON tl.lock_owner_address = wt.resource_address
    INNER JOIN sys.dm_exec_connections ec1
    ON ec1.session_id = tl.request_session_id
    INNER JOIN sys.dm_exec_connections ec2
    ON ec2.session_id = wt.blocking_session_id
    LEFT OUTER JOIN master.dbo.sysprocesses sp
    ON SP.spid = wt.blocking_session_id
    CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
    CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
    FOR XML PATH('tr'), TYPE
    ) AS NVARCHAR(MAX) ) +
    N'</table>'
    IF @HtmlContent  IS NOT NULL
    BEGIN
    EXEC msdb.dbo.sp_send_dbmail
    @profile_name = @ProfileName    ,
    @recipients   = @RecipientsLst    ,
    @subject      = @EmailSubject    ,
    @body         = @HtmlContent    ,
    @body_format  = 'HTML' ;
    END
    END
    END
    GO
      最后在數據庫新建一個作業,調用該存儲過程,然后在某段時間啟用作業監控數據庫的阻塞情況,作業的執行頻率是個比較難以定奪的頭痛問題,具體要根據系統情況來決定,我習慣2分鐘執行一次。
      最后,這個腳本還有一個問題,如果阻塞或被阻塞的SQL語句是某個存儲過程里面的一段腳本,顯示的SQL是整個存儲過程,而不是正在執行的SQL語句,目前還沒有想到好的方法解決這個問題。我目前手工去查看阻塞情況,如果非要查看存儲過程里面被阻塞的正在執行的SQL,一般結合下面SQL語句查看(輸入阻塞或被阻塞會話ID替代@sessionid)
    SELECT   [Spid] = er.session_id
    ,[ecid]
    ,[Database] = DB_NAME(sp.dbid)
    ,[Start_Time]
    ,[SessionRunTime]    = datediff(SECOND, start_time,getdate())
    ,[SqlRunTime]=     RIGHT(convert(varchar,
    dateadd(ms, datediff(ms, sp.last_batch, getdate()), '1900-01-01'),
    121), 12)
    ,[HostName]
    ,[Users]=COALESCE(sp.LOGINAME, sp.nt_username)
    ,[Status] = er.status
    ,[WaitType] = er.wait_type
    ,[Waitime] = er.wait_time/1000
    ,[Individual Query] = SUBSTRING(qt.text, er.statement_start_offset / 2,
    ( CASE WHEN er.statement_end_offset = -1
    THEN LEN(CONVERT(NVARCHAR(MAX), qt.text))
    * 2
    ELSE er.statement_end_offset
    END - er.statement_start_offset ) / 2)
    ,[Parent Query] = qt.text
    ,[PROGRAM_NAME] = program_name
    FROM    sys.dm_exec_requests er
    INNER JOIN sys.sysprocesses sp ON er.session_id = sp.spid
    CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) AS qt
    WHERE   session_Id = @sessionid;
    English »
     
    Text-to-speech function is limited to 100 characters

    posted @ 2014-06-04 10:49 順其自然EVO 閱讀(351) | 評論 (0)編輯 收藏

    Redis安裝及簡單測試

     摘要: Redis是目前業界非常受到歡迎的一個內存數據庫,一般用作系統的中間緩存系統,用以提升整體商業系統的吞吐量和響應速度。本文將簡要介紹安裝的主要過程以及給出一個簡要的測試代碼。
      1.  系統環境和版本說明
      操作系統選用Ubuntu 14.04, Redis的版本選取目前的最新穩定版本2.8.9. 客戶端選用了Redis的Java版本jedis 2.4.2.
      2.  Redis的安裝步驟
      a. 下載Redis的安裝包
      wget http://download.redis.io/releases/redis-2.8.9.tar.gz
      b. 在目錄下,解壓按照包,生成新的目錄redis-2.8.9
      tar xvfz redis-2.8.9.tar.gz
      c.  進入解壓之后的目錄,進行編譯
      cd redis-2.8.9
      sudo make
      說明: 如果沒有明顯的錯誤,則表示編譯成功
      d.  安裝
      sudo make install
      說明: 一般情況下,在Ubuntu系統中,都是需要使用sudo提升權限的

     e.   在安裝成功之后,可以運行測試,確認Redis的功能是否正常
      sudo make test
      f.  啟動Redis服務
      查找Redis安裝的目錄:  find /  -name 'redis*'  ------ 在根目錄下查找名稱中含有redis的文件
      經過查找,發現Redis被安裝到了/usr/local/bin/目錄下。
      接下來,啟動Redis服務:
      /usr/local/bin/redis-server
      說明: 從以上的截圖中,可以發現啟動的端口為缺省的6379. 用戶可以在啟動的時候,指定具體的配置文件,并在其中指定啟動的端口。
      g.  查看Redis進程
      ps -ef | grep redis
      說明: 如果可以看到進程,說明啟動正常。  3.   簡單的Redis測試程序
      讀者可以自行創建Eclipse項目,引入jedis的客戶端包,測試程序如下:
    public class RedisTest {
    private Jedis jedis = null;
    private String key1 = "key1";
    private String key2 = "key2";
    public RedisTest() {
    jedis = new Jedis("localhost");
    }
    public static void main(String[] args) {
    RedisTest redisTest = new RedisTest();
    redisTest.isReachable();
    redisTest.testData();
    redisTest.delData();
    redisTest.testExpire();
    }
    public boolean isReachable() {
    boolean isReached = true;
    try {
    jedis.connect();
    jedis.ping();
    // jedis.quit();
    } catch (JedisConnectionException e) {
    e.printStackTrace();
    isReached = false;
    }
    System.out
    .println("The current Redis Server is Reachable:" + isReached);
    return isReached;
    }
    public void testData() {
    jedis.set("key1", "data1");
    System.out.println("Check status of data existing:"
    + jedis.exists(key1));
    System.out.println("Get Data key1:" + jedis.get("key1"));
    long s = jedis.sadd(key2, "data2");
    System.out.println("Add key2 Data:" + jedis.scard(key2)
    + " with status " + s);
    }
    public void delData() {
    long count = jedis.del(key1);
    System.out.println("Get Data Key1 after it is deleted:"
    + jedis.get(key1));
    }
    public void testExpire() {
    long count = jedis.expire(key2, 5);
    try {
    Thread.currentThread().sleep(6000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    if (jedis.exists(key2)) {
    System.out
    .println("Get Key2 in Expire Action:" + jedis.scard(key2));
    } else {
    System.out.println("Key2 is expired with value:"
    + jedis.scard(key2));
    }
    }
    }
    public class RedisTest {
    private Jedis jedis = null;
    private String key1 = "key1";
    private String key2 = "key2";
    public RedisTest() {
    jedis = new Jedis("localhost");
    }
    public static void main(String[] args) {
    RedisTest redisTest = new RedisTest();
    redisTest.isReachable();
    redisTest.testData();
    redisTest.delData();
    redisTest.testExpire();
    }
    public boolean isReachable() {
    boolean isReached = true;
    try {
    jedis.connect();
    jedis.ping();
    // jedis.quit();
    } catch (JedisConnectionException e) {
    e.printStackTrace();
    isReached = false;
    }
    System.out
    .println("The current Redis Server is Reachable:" + isReached);
    return isReached;
    }
    public void testData() {
    jedis.set("key1", "data1");
    System.out.println("Check status of data existing:"
    + jedis.exists(key1));
    System.out.println("Get Data key1:" + jedis.get("key1"));
    long s = jedis.sadd(key2, "data2");
    System.out.println("Add key2 Data:" + jedis.scard(key2)
    + " with status " + s);
    }
    public void delData() {
    long count = jedis.del(key1);
    System.out.println("Get Data Key1 after it is deleted:"
    + jedis.get(key1));
    }
    public void testExpire() {
    long count = jedis.expire(key2, 5);
    try {
    Thread.currentThread().sleep(6000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    if (jedis.exists(key2)) {
    System.out
    .println("Get Key2 in Expire Action:" + jedis.scard(key2));
    } else {
    System.out.println("Key2 is expired with value:"
    + jedis.scard(key2));
    }
    }
    }
      4. 總結
      本文簡要直觀介紹了Redis的安裝和部署,并基于jedis的簡單測試程序,說明了Redis的基本使用情況,更多的內容,可以查閱相關資料。

    posted @ 2014-06-03 09:59 順其自然EVO 閱讀(591) | 評論 (0)編輯 收藏

    JSP網頁防止sql注入攻擊

      SQL注入攻擊指的是通過構建特殊的輸入作為參數傳入Web應用程序,而這些輸入大都是SQL語法里的一些組合,通過執行SQL語句進而執行攻擊者所要的操作,其主要原因是程序沒有細致地過濾用戶輸入的數據,致使非法數據侵入系統。
      prepareStatement方法是防止sql注入的簡單有效手段
      preparedStatement和statement的區別
      1、preparedStatement是statement的子方法
      2、preparedStatement可以防止sql注入的問題
      3、preparedStatement它可以對它所代表的sql語句進行預編譯,以減輕服務器壓力
      實例如下 
    public User find(String username, String password) {
    Connection conn = null;
    PreparedStatement st = null;
    ResultSet rs = null;
    try{
    conn = JdbcUtils.getConnection();
    String sql = "select * from users where username=? and password=?";
    st = conn.prepareStatement(sql);
    st.setString(1, username);
    st.setString(2, password);
    rs = st.executeQuery(); //
    if(rs.next()){
    User user = new User();
    user.setId(rs.getString("id"));
    user.setUsername(rs.getString("username"));
    user.setPassword(rs.getString("password"));
    user.setEmail(rs.getString("email"));
    user.setBirthday(rs.getDate("birthday"));
    return user;
    }
    return null;
    }catch (Exception e) {
    throw new DaoException(e);
    }finally{
    JdbcUtils.release(conn, st, rs);
    }

    posted @ 2014-06-03 09:58 順其自然EVO 閱讀(415) | 評論 (1)編輯 收藏

    SQL數據排序與分組

    一、為什么要對數據進行分組
      數據分組:是按照邏輯次序把具有重復值的字段進行合并。
      二、GROUP BY子句
      語法:
    SELECT column1,column2
    FROM table1,table2
    WHERE conditions
    GROUP BY column1,column2
    ORDER BY column1,column2;
      1、分組函數
      典型的分組函數—也就是用于GROUP BY子句對數據進行劃分的函數—包括AVG、MAX、MIN、SUM、COUNT。
      2、對選中的數據進行分組
      數據分組是個簡單的過程。被選中的字段(查詢中SELECT之后的字段列表)才能在GROUP BY子句里引用;如果字段在SELECT語句里找不到,就不能用于GROUP BY子句。
      注:在對數據進行分組時,分組字段的次序不一定要與SELECT子句里字段次序相同。
      3、創建分組和使用匯總函數
      SELECT語句在使用GROUP BY子句時必須滿足一定條件。特別是被選中的字段必須出現在GROUP BY子句里,除了匯總函數。
      注:具體數值在排序時位于NULL值之前,字符型在排序時位于NULL值之后。
      4、以整數代表字段名稱
      像ORDER BY子句一樣,GROUP BY子句里也可以用整數代表字段名稱。
      三、GROUP BY和ORDER BY
      ORDER BY子句專門用于對查詢得到的數據進行排序,GROUP BY子句也把查詢得到的數據排序為適當分組的數據,因此,GROUP BY子句也可以像ORDER BY子句那樣用于數據排序。
      使用GROUP BY子句實現排序操作的區別與缺點:
      1、所有被選中的、非匯總函數的字段必須列在GROUP BY子句里;
      2、除非需要使用匯總函數,否則使用GROUP BY子句進行排序通常是沒有必要的。
      四、CUBE和ROLLUP語句
      ROLLUP語法:
      GROUP BY ROLLUP(ordered column list of grouping sets)
      MySQL ROLLUP語法:
      GROUP BY order column list of grouping sets WITH ROLLUP
      ROLLUP語句的工作方式:
      1、在完成了基本的分組數據匯總以后,
      2、按照從右向左的順序,每次去掉字段列表中的最后一個字段,再對剩余的字段進行分組統計,并將獲得的小計結果插入返回表中,被去掉的字段位置使用NULL填充。
      3、最后,再對全表進行一次統計,所有的字段位置均使用NULL填充。
      CUBE語法:
      GROUP BY CUBE(column list of grouping sets)
      CUBE語句在SQL Server和Oracle中都可以使用,MySQL尚不支持該語句。
      CUBE語句的工作方式:
      1、它對分組列表中的所有字段進行排列組合,并根據每一種組合結果,分別進行統計匯總。    2、最后,CUBE語句也會對全表進行統計。
      五、HAVING子句
      HAVING子句必須跟在GROUP BY子句之后,在ORDER BY子句之前。
    語法:
    SELECT column1,column2
    FROM table1,table2
    WHERE contidions
    GROUP BY column1,column2
    HAVING conditions
    ORDER BY column1,column2;

    posted @ 2014-06-03 09:56 順其自然EVO 閱讀(219) | 評論 (0)編輯 收藏

    Java基于Socket文件傳輸示例

    最近需要進行網絡傳輸大文件,于是對基于socket的文件傳輸作了一個初步的了解。在一位網友提供的程序基礎上,俺進行了一些加工,采用了緩沖輸入/輸出流來包裝輸出流,再采用數據輸入/輸出輸出流進行包裝,加快傳輸的速度。廢話少說,先來看服務器端的程序。
      1.服務器端
    package sterning;
    import java.io.BufferedInputStream;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    public class ServerTest {
    int port = 8821;
    void start() {
    Socket s = null;
    try {
    ServerSocket ss = new ServerSocket(port);
    while (true) {
    // 選擇進行傳輸的文件
    String filePath = "D:\\lib.rar";
    File fi = new File(filePath);
    System.out.println("文件長度:" + (int) fi.length());
    // public Socket accept() throws
    // IOException偵聽并接受到此套接字的連接。此方法在進行連接之前一直阻塞。
    s = ss.accept();
    System.out.println("建立socket鏈接");
    DataInputStream dis = new DataInputStream(new BufferedInputStream(s.getInputStream()));
    dis.readByte();
    DataInputStream fis = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath)));
    DataOutputStream ps = new DataOutputStream(s.getOutputStream());
    //將文件名及長度傳給客戶端。這里要真正適用所有平臺,例如中文名的處理,還需要加工,具體可以參見Think In Java 4th里有現成的代碼。
    ps.writeUTF(fi.getName());
    ps.flush();
    ps.writeLong((long) fi.length());
    ps.flush();
    int bufferSize = 8192;
    byte[] buf = new byte[bufferSize];
    while (true) {
    int read = 0;
    if (fis != null) {
    read = fis.read(buf);
    }
    if (read == -1) {
    break;
    }
    ps.write(buf, 0, read);
    }
    ps.flush();
    // 注意關閉socket鏈接哦,不然客戶端會等待server的數據過來,
    // 直到socket超時,導致數據不完整。
    fis.close();
    s.close();
    System.out.println("文件傳輸完成");
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    public static void main(String arg[]) {
    new ServerTest().start();
    }
    }
    2.socket的Util輔助類
    package sterning;
    import java.net.*;
    import java.io.*;
    public class ClientSocket {
    private String ip;
    private int port;
    private Socket socket = null;
    DataOutputStream out = null;
    DataInputStream getMessageStream = null;
    public ClientSocket(String ip, int port) {
    this.ip = ip;
    this.port = port;
    }
    /** *//**
    * 創建socket連接
    *
    * @throws Exception
    *             exception
    */
    public void CreateConnection() throws Exception {
    try {
    socket = new Socket(ip, port);
    } catch (Exception e) {
    e.printStackTrace();
    if (socket != null)
    socket.close();
    throw e;
    } finally {
    }
    }
    public void sendMessage(String sendMessage) throws Exception {
    try {
    out = new DataOutputStream(socket.getOutputStream());
    if (sendMessage.equals("Windows")) {
    out.writeByte(0x1);
    out.flush();
    return;
    }
    if (sendMessage.equals("Unix")) {
    out.writeByte(0x2);
    out.flush();
    return;
    }
    if (sendMessage.equals("Linux")) {
    out.writeByte(0x3);
    out.flush();
    } else {
    out.writeUTF(sendMessage);
    out.flush();
    }
    } catch (Exception e) {
    e.printStackTrace();
    if (out != null)
    out.close();
    throw e;
    } finally {
    }
    }
    public DataInputStream getMessageStream() throws Exception {
    try {
    getMessageStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
    return getMessageStream;
    } catch (Exception e) {
    e.printStackTrace();
    if (getMessageStream != null)
    getMessageStream.close();
    throw e;
    } finally {
    }
    }
    public void shutDownConnection() {
    try {
    if (out != null)
    out.close();
    if (getMessageStream != null)
    getMessageStream.close();
    if (socket != null)
    socket.close();
    } catch (Exception e) {
    }
    }
    }
     3.客戶端
    package sterning;
    import java.io.BufferedOutputStream;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.FileOutputStream;
    public class ClientTest {
    private ClientSocket cs = null;
    private String ip = "localhost";// 設置成服務器IP
    private int port = 8821;
    private String sendMessage = "Windwos";
    public ClientTest() {
    try {
    if (createConnection()) {
    sendMessage();
    getMessage();
    }
    } catch (Exception ex) {
    ex.printStackTrace();
    }
    }
    private boolean createConnection() {
    cs = new ClientSocket(ip, port);
    try {
    cs.CreateConnection();
    System.out.print("連接服務器成功!" + "\n");
    return true;
    } catch (Exception e) {
    System.out.print("連接服務器失敗!" + "\n");
    return false;
    }
    }
    private void sendMessage() {
    if (cs == null)
    return;
    try {
    cs.sendMessage(sendMessage);
    } catch (Exception e) {
    System.out.print("發送消息失敗!" + "\n");
    }
    }
    private void getMessage() {
    if (cs == null)
    return;
    DataInputStream inputStream = null;
    try {
    inputStream = cs.getMessageStream();
    } catch (Exception e) {
    System.out.print("接收消息緩存錯誤\n");
    return;
    }
    try {
    //本地保存路徑,文件名會自動從服務器端繼承而來。
    String savePath = "E:\\";
    int bufferSize = 8192;
    byte[] buf = new byte[bufferSize];
    int passedlen = 0;
    long len=0;
    savePath += inputStream.readUTF();
    DataOutputStream fileOut = new DataOutputStream(new BufferedOutputStream(new BufferedOutputStream(new FileOutputStream(savePath))));
    len = inputStream.readLong();
    System.out.println("文件的長度為:" + len + "\n");
    System.out.println("開始接收文件!" + "\n");
    while (true) {
    int read = 0;
    if (inputStream != null) {
    read = inputStream.read(buf);
    }
    passedlen += read;
    if (read == -1) {
    break;
    }
    //下面進度條本為圖形界面的prograssBar做的,這里如果是打文件,可能會重復打印出一些相同的百分比
    System.out.println("文件接收了" +  (passedlen * 100/ len) + "%\n");
    fileOut.write(buf, 0, read);
    }
    System.out.println("接收完成,文件存為" + savePath + "\n");
    fileOut.close();
    } catch (Exception e) {
    System.out.println("接收消息錯誤" + "\n");
    return;
    }
    }
    public static void main(String arg[]) {
    new ClientTest();
    }
    }
      這就實現了從服務器端向客戶端發送文件的過程,當然,反過來,也一樣.稍有不同.代碼中對跨平臺的細節沒有實現,有時間或興趣的朋友可以提供一下.

    posted @ 2014-06-03 09:54 順其自然EVO 閱讀(197) | 評論 (0)編輯 收藏

    Linux內核移植問題總結

    移植一個內核會涉及到很多東西,對想學arm的人來說還是挺有幫助的,會比直接拿別人移植好的內核來跑有趣的多。
      一、串口打印問題
      內核移植的第一步就是要有打印輸出。看不到打印信息,都不知道內核有沒有跑起來。我移植 linux-2.6.35編譯完成后運行,啟動一直停在starting kernel . . .,檢查machine-type、cpu-id、時鐘、入口地址等可能會導致問題的地方都沒有問題,最后想到可能是串口使用的引腳和內核不一致,最后才發現板子使用的是串口2作為打印輸出(也是我一開始沒想到的,因為一般都會默認使用串口1,糾結)。講啟動參數改成串口2,mx5_loco.c 里面的init串口改成UART2_BASE_ADDR,可以輸出信息了。
      二、文件系統
      1、自己編譯一個busybox來制作一個文件系統其實還是挺麻煩的,只能制作一個很簡單的文件系統,因為是在flash上加載,所以我最開始嘗試的是cramfs,加載文件系統階段一直出錯
      List of all partitions:
      1f00          131072 mtdblock0  (driver?)
      No filesystem could mount root, tried:  cramfs
      Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(31,0)
      這里只讀到了一個塊設備,block0,顯然flash的分區沒有成功,修改nandflash的分區,文件系統正常加載,啟動參數如下
      setenv bootargs root=/dev/mtdblock3 rootfstype=cramfs rw console=ttymxc1,115200 init=/linuxrc
      2、加載成功有時會出現Kernel panic - not syncing: Attempted to kill init!,這個很多人說要開
      Kernel Features  --->
      [*] Use the ARM EABI to compile the kernel
      [*]   Allow old ABI binaries to run with this kernel (EXPERIMENTAL)(NEW)
      我試過好像沒什么效果,出現這個問題有可能是文件系統的inittab和rcS兩個文件有問題。
      3、jffs2文件系統
      JFFS2 error: (1) jffs2_build_inode_pass1: child dir"alsa" (ino #1159) of dir ino #1074 appears to be a hard link  JFFS2 error: (1) jffs2_build_inode_pass1:child dir "l" (ino #1170) of dir ino #1075 appears to be a hard link
      原由 : flash沒有erase徹底.,多 nand erase幾次就好了
      還有就是jffs2文件系統會有很多警告信息,我在源碼里面將打印都去掉還是不行

    posted @ 2014-06-03 09:52 順其自然EVO 閱讀(561) | 評論 (0)編輯 收藏

    前端自動化測試工具doh學習總結(一)

     前言
      項目中需要用到前端自動化測試,自己被當作一個探針研究了下目前用的比較多的web自動化測試工具。一開始研究的是的selenium,但由于項目使用了大量的dijit控件,寫起testCase來很費勁;最主要的是selenium有嚴重的瀏覽器兼容性問題,于是徹底放棄,改投doh門下,畢竟是dojo他爸爸開發的跟dojo繼承起來非常方便。這幾篇主要介紹doh、doh/Robot以及將doh與selenium結合進而與CI工具集成起來。
      一、DOH 是什么
      DOH 是 Dojo Objective Harness 的簡稱,是 Dojo 在 0.9 版本之后新增的單元測試工具。隨著 Javascript 代碼的數量和復雜度的增加,Web 前端開發者也需要一個 Javascript 代碼的單元測試框架來保證自己寫出來的 Javascript 代碼是健壯的。所以,DOH 是 Web 前端開發者對 JUnit 的回應。DOH有如下特點:
      提供用戶界面:JUnit中的紅條測試失敗、綠條測試通過,大家都已經很熟悉了,DOH也有類似的用戶界面,用戶在測試時更加一目了然;
      平臺無關:DOH并不依賴某種瀏覽器平臺,甚至不依賴于瀏覽器;用戶可以根據自己的需要在命令行進行Javascript的自動化單元測試;
      支持Ajax:Ajax編程在Web前端開發中是必不可少的一環,DOH最有價值的一個特性就是支持Ajax的測試;
      不只適合與于Dojo,可用于任何JavaScript程序的單元測試。
      下載dojo源碼包,解壓后可以看到以下目錄:
      二、DOH第一次親密接觸
      部署到服務器后,我們訪問runner.html
      與JUnit類似,DOH也為我們提供了一個類似的界面,左側表示運行的測試案例,右側是測試日志,最上方的進度條表示的是本次運行中的已執行案例,同樣綠色表示成功,紅色表示失敗。默認情況下會加載“dojo/tests/module.js”文件,該文件的作用就是像runner.html中加載dojo所有核心模塊的測試案例。
      如果想要單獨加載某一模塊的測試案例,需要用到test參數指向該模塊:
      http://<server>/util/doh/runner.html?test=dojo/tests/fx
    我們可以吧測試案例放到自己的項目目錄下,通過test參數指向自定義測試模塊,這時需要用到paths參數:
      util/doh/runner.html?paths=org/myorg,../../../mycode/org/myorg&test=org/myorg/mymodule/tests/alltests
      paths參數中逗號前后的值相當于dojoConfig定義packages對象時的name和location
      同樣在path中我們可以定義多個模塊, 模塊之間用“;”分隔開來
      util/doh/runner.html?paths=org/myorg,../../../mycode/org/myorg;com/mycom,../../../x/com/mycom&test=com/mycom/tests
      doh中測試模塊要么是一個用來請求多個測試文件的文件,要么是一個使用doh.register方法注冊時測試案例,或者兩者皆有。
      define([
      "my/test/widget/Foo0",
      "my/test/widget/Foo1",
      "my/test/widget/Foo2"
      ]);
    doh.register(...)
    An almost 'magical' function. The doh.register() method accepts the function signatures of any of the other registration functions and determines the correct underlying function (listed below) to dispatch registration to. It's the function you'll most commonly use for registering Unit Tests.
    doh.registerTest(group, testFuncOrObj)
    This function registers a test as a member of the group 'group', and the test can either be a simple function definition or a 'Test Fixture', which is an object that defines the run requirements of the test.
    doh.registerTests(group, testFuncOrObjArr)
    This function registers an array of tests as a member of the group 'group'. The contents of the array of tests can be an array of simple test functions or an array of 'test fixtures', or a mix of them.
    doh.registerTestNs(group, obj)
    This function registers an object comprised of functions as a member of the group 'group'. Note that this function will only add in non-private (functions without an _ at the beginning of the name), as a test function. If you'd like to use fixtures (setUp(), tearDown(), and runTest()), please use doh.register(), doh.registerTest() or doh.registerTests().
    doh.registerTestUrl(url)
    This function registers a URL as a location to load tests from. The URL is used to populate the contents of an iframe, and usually refers to an HTML page that boot-loads D.O.H. internally for running tests in a segmented iframe. A good example showing this is the dojo/tests/fx.html. It loads dojo, doh, and then on dojo load completion calls doh.registerTests(). The D.O.H. instance in the iframe will proxy back the results of the test run to the primary D.O.H. instance.
      上面提到的dojo/test/fx模塊中我們可以看到該文件中主要定義了兩個TestSuite:
      define(["doh/main", "require"], function(doh, require){
      if(doh.isBrowser){
      doh.register("tests.fx", require.toUrl("./fx.html"), 30000);
      doh.register("tests.NodeList-fx", require.toUrl("./NodeList-fx.html"), 30000);
      }
      });
      對應于runner.html中
      打開該目錄下的fx.html文件,我們可以看到該文件中定義了一系列TestCase
      doh中有兩種測試結構:
      1、Simple Tests  將一個單獨的函數放到doh.register參數testCase數組里
      同步形式:
      function mySimpleTest(doh){
      doh.assertTrue(true);
      }
      異步形式:
    function mySimpleAsyncTest(doh){
    var deferred = new doh.Deferred();
    setTimeout(deferred.getTestCallback(function(){
    doh.assertTrue(true);
    }), 100);
    return deferred;
    }
      2、Test Fixture
      同步形式:
    {
    name: "thingerTest",
    setUp: function(){
    // Setup to do before runTest.//類似于JUnit中的@beforeTest
    this.thingerToTest = new Thinger();
    this.thingerToTest.doStuffToInit();
    },
    runTest: function(){
    // Our test function to run.//類似于JUnit中的@Test
    doh.assertEqual("blah", this.thingerToTest.blahProp);
    doh.assertFalse(this.thingerToTest.falseProp);
    // ...
    },
    tearDown: function(){
    // cleanup to do after runTest.//類似于JUnit中的@afterTest
    },
    timeout: 3000 // 3 second timeout.//測試運行時間,超過改時間會報錯
    }
      異步形式:
    {
    name: "thingerTest",
    setUp: function(){
    // Setup to do before runTest.
    this.thingerToTest = new Thinger();
    this.thingerToTest.doStuffToInit();
    },
    runTest: function(){
    // Our test function to run.
    var deferred = new doh.Deferred();
    setTimeout(deferred.getTestCallback(function(){
    doh.assertEqual("blah", this.thingerToTest.blahProp);
    doh.assertFalse(this.thingerToTest.falseProp);
    }), 100);
    return deferred;
    },
    tearDown: function(){
    // cleanup to do after runTest.
    },
    timeout: 3000 // 3 second timeout.
    }

    posted @ 2014-05-29 11:42 順其自然EVO 閱讀(623) | 評論 (0)編輯 收藏

    僅列出標題
    共394頁: First 上一頁 104 105 106 107 108 109 110 111 112 下一頁 Last 
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产福利在线免费| 国产精品无码亚洲精品2021| 在线观看免费亚洲| 99re6在线视频精品免费下载 | 美女视频黄的免费视频网页| 亚洲狠狠婷婷综合久久| 亚洲成a人片77777群色| 亚洲第一AV网站| 中文字幕亚洲乱码熟女一区二区| 免费高清在线爱做视频| 无码国产精品一区二区免费虚拟VR| 久久国产精品成人免费| 中文字幕无线码免费人妻| 老司机午夜在线视频免费观| 亚洲另类无码专区首页| 亚洲sss综合天堂久久久| 亚洲天堂福利视频| 亚洲精品午夜在线观看| 久久精品亚洲一区二区三区浴池| 国产亚洲精品无码成人| 国产亚洲精品拍拍拍拍拍| 亚洲精品视频免费观看| 亚洲AⅤ视频一区二区三区| 国产精品美女午夜爽爽爽免费| 久久午夜夜伦鲁鲁片免费无码影视 | 曰批全过程免费视频观看免费软件 | 日韩精品无码免费专区午夜不卡 | 亚洲综合色自拍一区| 国产av无码专区亚洲国产精品| 啊v在线免费观看| 免费成人午夜视频| 亚洲av午夜精品一区二区三区| 国产大片免费观看中文字幕| 国产高清在线免费视频| 免费真实播放国产乱子伦| 亚洲精品无码久久久| 国产偷窥女洗浴在线观看亚洲| 久久精品国产精品亚洲| 亚洲日韩精品无码专区网址 | 黄色网站软件app在线观看免费 | 亚洲一区二区三区在线播放|