• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

    ASP程序性能測試報告

    發布: 2007-11-13 10:46 | 作者: 網絡轉載 | 來源: 網絡轉載 | 查看: 138次 | 進入軟件測試論壇討論

    領測軟件測試網     綱要:ASP動態生成的內容以什么方式輸出效率最高?最好用哪種方法提取數據庫記錄集?本文測試了近20個這類ASP開發中常見的問題,測試工具所顯示的時間告訴我們:這些通?梢韵氘斎坏膯栴}不僅值得關注,而且還有出乎意料的秘密隱藏在內。

    一、測試目的

       本文的第一部分考察了ASP開發中的一些基本問題,給出了一些性能測試結果以幫助讀者理解放入頁面的代碼到底對性能有什么影響。ADO是由Microsoft開發的一個通用、易用的數據庫接口,事實證明通過ADO與數據庫交互是ASP最重要的應用之一,在第二部分中,我們就來研究這個問題。

       ADO所提供的功能相當廣泛,因此準備本文最大的困難在于如何界定問題的范圍?紤]到提取大量的數據可能顯著地增加Web服務器的負載,所以我們決定這一部分的主要目的是找出什么才是操作ADO記錄集的最優配置。然而,即使縮小了問題的范圍,我們仍舊面臨很大的困難,因為ADO可以有許多種不同的方法來完成同一個任務。例如,記錄集不僅可以通過Recordset類提取,而且也可以通過Connection和Command類提;即使得到記錄集對象之后,還有許多可能戲劇性地影響性能的操作方法。然而,與第一部分一樣,我們將盡可能地涵蓋最廣泛的問題。

       具體地講,這一部分的目標是收集足夠多的信息,回答下列問題:

    l是否應該通過包含引用ADOVBS.inc?
    l使用記錄集時是否應該創建單獨的連接對象?
    l最好用哪種方法提取記錄集?
    l哪種游標類型和記錄鎖定方式效率最高?
    l是否應該使用本地記錄集?
    l設置記錄集屬性用哪種方法最好?
    l用哪種方法引用記錄集字段值效率最高?
    l用臨時字符串收集輸出是一種好方法嗎?

    二、測試環境

       本測試總共用到了21個ASP文件,這些文件可以從本文后面下載。每一個頁面設置成可以運行三種不同的查詢,分別返回0、25、250個記錄。這將幫助我們隔離頁面本身的初始化、運行開銷與用循環訪問記錄集的開銷。

       為便于測試,數據庫連接字符串和SQL命令串都在Global.asa中作為Application變量保存。由于我們的測試數據庫是SQL Server 7.0,因此連接串指定OLEDB作為連接提供者,測試數據來自SQL Server的Northwind數據庫。SQL SELECT命令從NorthWind Orders表提取7個指定的字段。

    < SCRIPT LANGUAGE=VBScript RUNAT=Server >
    Sub Application_OnStart
    Application("Conn") = "Provider=SQLOLEDB; " & _
    "Server=MyServer; " & _
    "uid=sa; " & _
    "pwd=;" & _
    "DATABASE=northwind"
    Application("SQL") = "SELECTTOP 0OrderID, " & _
    "CustomerID, " & _
    "EmployeeID, " & _
    "OrderDate, " & _
    "RequiredDate, " & _
    "ShippedDate, " & _
    "Freight " & _
    "FROM[Orders] "
    End Sub
    < /SCRIPT >

    'alternate sql - 25 records
    Application("SQL") = "SELECTTOP 25OrderID, " & _
    "CustomerID, " & _
    "EmployeeID, " & _
    "OrderDate, " & _
    "RequiredDate, " & _
    "ShippedDate, " & _
    "Freight " & _
    "FROM[Orders] "

    'alternate sql - 250 records
    Application("SQL") = "SELECTTOP 250 OrderID, " & _
    "CustomerID, " & _
    "EmployeeID, " & _
    "OrderDate, " & _
    "RequiredDate, " & _
    "ShippedDate, " & _
    "Freight " & _
    "FROM[Orders] "

       測試服務器配置如下:450 Mhz Pentium,512 MB RAM,NT Server 4.0 SP5,MDAC 2.1(數據訪問組件),以及5.0版本的Microsoft腳本引擎。SQL Server運行在另外一臺具有類似配置的機器上。和第一部分一樣,我們仍舊使用Microsoft Web Application Stress Tool 記錄從第一個頁面請求到從服務器接收到最后一個字節的時間(TTLB,Time To Last Byte),時間以毫秒為單位。測試腳本調用每個頁面1300次以上,運行時間約20小時,以下顯示的時間是會話的平均TTLB。請記住,和第一部分一樣,我們只關心代碼的效率,而不是它的可伸縮性或服務器性能。

       同時請注意我們啟用了服務器的緩沖。另外,為了讓所有的文件名字長度相同,有的文件名字中嵌入了一個或多個下劃線。
    三、第一次測試

       在第一次測試中,我們模擬Microsoft ASP ADO示例中可找到的典型情形提取一個記錄集。在這個例子(ADO__01.asp)中,我們首先打開一個連接,然后創建記錄集對象。當然,這里的腳本按照本文第一部分所總結的編碼規則作了優化。

    < % Option Explicit % >
    < !-- #Include file="ADOVBS.INC" -- >
    < %
    Dim objConn
    Dim objRS

    Response.Write( _
    "< HTML >< HEAD >" & _
    "< TITLE >ADO Test< /TITLE >" & _
    "< /HEAD >< BODY >" _
    )

    Set objConn = Server.CreateObject("ADODB.Connection")
    objConn.Open Application("Conn")

    Set objRS = Server.CreateObject("ADODB.Recordset")
    objRS.ActiveConnection = objConn
    objRS.CursorType = adOpenForwardOnly
    objRS.LockType = adLockReadOnly
    objRS.Open Application("SQL")

    If objRS.EOF Then
    Response.Write("No Records Found")
    Else
    'write headings
    Response.Write( _
    "< TABLE BORDER=1 >" & _
    "< TR >" & _
    "< TH >OrderID< /TH >" & _
    "< TH >CustomerID< /TH >" & _
    "< TH >EmployeeID< /TH >" & _
    "< TH >OrderDate< /TH >" & _
    "< TH >RequiredDate< /TH >" & _
    "< TH >ShippedDate< /TH >" & _
    "< TH >Freight< /TH >" & _
    "< /TR >" _
    )
    'write data
    Do While Not objRS.EOF
    Response.Write( _
    "< TR >" & _
    "< TD >" & objRS("OrderID") & "< /TD >" & _
    "< TD >" & objRS("CustomerID") & "< /TD >" & _
    "< TD >" & objRS("EmployeeID") & "< /TD >" & _
    "< TD >" & objRS("OrderDate") & "< /TD >" & _
    "< TD >" & objRS("RequiredDate") & "< /TD >" & _
    "< TD >" & objRS("ShippedDate") & "< /TD >" & _
    "< TD >" & objRS("Freight") & "< /TD >" & _
    "< /TR > " _
    )
    objRS.MoveNext
    Loop
    Response.Write("< /TABLE >")
    End If

    objRS.Close
    objConn.Close
    Set objRS = Nothing
    Set objConn = Nothing

    Response.Write("< /BODY >< /HTML >")
    % >

       下面是測試結果:

       我們來看一下各欄數字的含義:
    0返回0個記錄的頁面所需要的TTLB(毫秒)。在所有的測試中,該值被視為生成頁面本身(包括創建對象)的時間開銷,不包含循環訪問記錄集數據的時間。
    25以毫秒計的提取和顯示25個記錄的TTLB
    tot time/25"25"欄的TTLB除以25,它是每個記錄的總計平均時間開銷。
    disp time/25"25"欄的TTLB減去"0"欄的TTLB,然后除以25。該值反映了在循環記錄集時顯示單個記錄所需時間。
    250提取和顯示250個記錄的TTLB。
    tot time/250"250"欄的TTLB除以25,該值代表單個記錄的總計平均時間開銷。
    disp time/250"250"欄的TTLB減去"0"欄的TTLB,再除以250。該值反映了在循環記錄集時顯示單個記錄所需時間。

       上面的測試結果將用來同下一個測試結果比較。
    四、是否應該通過包含引用ADOVBS.inc?

       Microsoft提供的ADOVBS.inc包含了270行代碼,這些代碼定義了大多數的ADO屬性常量。我們這個示例只從ADOVBS.inc引用了2個常量。因此本次測試(ADO__02.asp)中我們刪除了包含文件引用,設置屬性時直接使用相應的數值。

    objRS.CursorType = 0?' adOpenForwardOnly
    objRS.LockType = 1' adLockReadOnly


       可以看到頁面開銷下降了23%。該值并不影響單個記錄的提取和顯示時間,因為這里的變化不會影響循環內的記錄集操作。有多種方法可以解決ADOVBS.inc的引用問題。我們建議將ADOVBS.inc文件作為參考,設置時通過注釋加以說明。請記住,正如第一部分所指出的,適度地運用注釋對代碼的效率影響極小。另外一種方法是將那些需要用到的常量從ADOVBS.inc文件拷貝到頁面內。

       還有一個解決該問題的好方法,這就是通過鏈接ADO類型庫使得所有的ADO常量直接可用。把下面的代碼加入Global.asa文件,即可直接訪問所有的ADO常量:

    < !--METADATA TYPE="typelib"
    FILE="C:Program FilesCommon FilesSYSTEMADOmsado15.dll"
    NAME="ADODB Type Library" -- >

    或者:

    < !--METADATA TYPE="typelib"
    UUID="00000205-0000-0010-8000-00AA006D2EA4"
    NAME="ADODB Type Library" -- >

       因此,我們的第一條規則為:

    l避免包含ADOVBS.inc文件,通過其他方法訪問和使用ADO常量。
    五、使用記錄集時是否應該創建單獨的連接對象?

       要正確地回答這個問題,我們必須分析兩種不同條件下的測試:第一,頁面只有一個數據庫事務;第二,頁面有多個數據庫事務。

       在前例中,我們創建了一個單獨的Connection對象并將它賦給Recordset的ActiveConnection屬性。然而,如ADO__03.asp所示,我們也可以直接把連接串賦給ActiveConnection屬性,在腳本中初始化和配置Connection對象這一額外的步驟可以省去。

    objRS.ActiveConnection = Application("Conn")

       雖然Recordset對象仍舊要創建一個連接,但此時的創建是在高度優化的條件下進行的。因此,與上一次測試相比,頁面開銷又下降了23%,而且如預期的一樣,單個記錄的顯示時間沒有實質的變化。

       因此,我們的第二個規則如下:

    l如果只使用一個記錄集,直接把連接串賦給ActiveConnection屬性。

       接下來我們檢查頁面用到多個記錄集時,上述規則是否仍舊有效。為測試這種情形,我們引入一個FOR循環將前例重復10次。在這個測試中,我們將研究三種變化:

       第一,如ADO__04.asp所示,在每一個循環中建立和拆除Connection對象:

    Dim i
    For i = 1 to 10

    Set objConn = Server.CreateObject("ADODB.Connection")
    objConn.Open Application("Conn")

    Set objRS = Server.CreateObject("ADODB.Recordset")
    objRS.ActiveConnection = objConn
    objRS.CursorType = 0 'adOpenForwardOnly
    objRS.LockType = 1 'adLockReadOnly
    objRS.Open Application("SQL")
    If objRS.EOF Then
    Response.Write("No Records Found")
    Else
    'write headings
    ...
    'write data
    ...
    End If

    objRS.Close
    Set objRS = Nothing
    objConn.Close
    Set objConn = Nothing

    Next

       第二,如ADO__05.asp所示,在循環外面創建Connection對象,所有記錄集共享該對象:

    Set objConn = Server.CreateObject("ADODB.Connection")
    objConn.Open Application("Conn")

    Dim i
    For i = 1 to 10
    Set objRS = Server.CreateObject("ADODB.Recordset")
    objRS.ActiveConnection = objConn
    objRS.CursorType = 0 'adOpenForwardOnly
    objRS.LockType = 1 'adLockReadOnly
    objRS.Open Application("SQL")

    If objRS.EOF Then
    Response.Write("No Records Found")
    Else
    'write headings
    ...
    'write data
    ...
    End If

    objRS.Close
    Set objRS = Nothing

    Next
    objConn.Close
    Set objConn = Nothing

       第三,如ADO__06.asp所示,在每一個循環內把連接串賦給ActiveConnection屬性:

    Dim i
    For i = 1 to 10

    Set objRS = Server.CreateObject("ADODB.Recordset")
    objRS.ActiveConnection = Application("Conn")
    objRS.CursorType = 0 'adOpenForwardOnly
    objRS.LockType = 1 'adLockReadOnly
    objRS.Open Application("SQL")

    If objRS.EOF Then
    Response.Write("No Records Found")
    Else
    'write headings
    ...
    'write data
    ...
    End If

    objRS.Close
    Set objRS = Nothing
    Next


       就象我們可以猜想到的一樣,在循環內創建和拆除連接對象是效率最差的方法。不過,令人驚異的是,在循環內直接把連接串賦給ActiveConnection屬性只比共享單個連接對象稍微慢了一點。

       盡管如此,第三規則應該為:

    l同一頁面內用到多個記錄集時,創建單一的連接對象并通過ActiveConnection屬性共享它。
    六、哪種游標類型和記錄鎖定方式效率最高?

       迄今為止的所有測試中我們只使用了“只能向前”的游標來訪問記錄集。ADO為記錄集提供的游標還有三種類型:靜態可滾動的游標,動態可滾動的游標,鍵集游標。每種游標都提供不同的功能,比如訪問前一記錄和后一記錄、是否可以看到其他程序對數據的修改等。不過,具體討論每一種游標類型的功用已經超出了本文的范圍,下表是各種游標類型的一個比較性的分析。

       和“只能向前”類型的游標相比,所有其它的游標類型都需要額外的開銷,而且這些游標在循環內一般也要慢一些。因此,我們愿與您共享如下告誡:永遠不要這樣認為——“唔,有時候我會用到動態游標,那么我就一直使用這種游標吧!

       同樣的看法也適用于記錄鎖定方式的選擇。前面的測試只用到了只讀的加鎖方式,但還存在其他三種方式:保守式、開放式、開放式批處理方式。和游標類型一樣,這些鎖定方式為處理記錄集數據提供了不同的功能和控制能力。

       我們得出如下規則:

    l使用適合于處理任務的最簡單的游標類型和記錄鎖定方式。
    七、最好用哪種方法提取記錄集?

       到目前為止我們一直通過創建Recordset對象提取記錄集,但是ADO也提供了間接的記錄集提取方法。下面的測試比較ADO__03.asp和直接從Connection對象創建記錄集(CONN_01.asp)這兩種方法:

    Set objConn = Server.CreateObject("ADODB.Connection")
    objConn.Open Application("Conn")

    Set objRS = objConn.Execute(Application("SQL"))

       可以看到頁面開銷略有增加,單個記錄的顯示時間沒有變化。

       下面我們再來看看從Command對象直接創建記錄集對象(CMD__02.asp):

    Set objCmd = Server.CreateObject("ADODB.Command")
    objCmd.ActiveConnection = Application("Conn")
    objCmd.CommandText = Application("SQL")

    Set objRS = objCmd.Execute

       同樣,頁面開銷也略有增加,而單個記錄的顯示時間沒有本質的變化。后面這兩種方法在性能上的差異很小,但我們還有一個重要的問題需要考慮。

       通過Recordset類創建記錄集時,我們能夠以最大的靈活性控制記錄集的處理方式。既然后面兩種方法未能有壓倒性的性能表現,我們主要還是考慮默認返回的游標類型和記錄鎖定方式,對于某些場合來說默認值并不一定是最理想的。

       因此,除非由于特殊的原因需要選擇后面兩種方法,否則我們建議考慮下面的規則:

    l通過ADODB.Recordset類實例化記錄集,以獲得最好的性能和靈活性。

    八、是否應該使用本地記錄集?

       ADO允許使用本地(客戶端)記錄集,此時查詢將提取記錄集內的所有數據,查詢完成后連接可以立即關閉,以后使用本地的游標訪問數據,這為釋放連接帶來了方便。使用本地記錄集對于訪問那些要求數據離線使用的遠程數據服務非常重要,那么,對于普通的應用它是否同樣有所幫助?

       下面我們加入CursorLocation屬性,并在打開記錄集之后關閉了連接(CLIENT1.asp):

    Set objRS = Server.CreateObject("ADODB.Recordset")
    objRS.CursorLocation = 2' adUseClient
    objRS.ActiveConnection = Application("Conn")
    objRS.LockType = 1?' adLockReadOnly
    objRS.Open Application("SQL")
    objRS.ActiveConnection = Nothing

       理論上,這種方法由于以下兩個原因會對效率有所好處:第一,它避免了在記錄之間移動時重復地通過連接請求數據;第二,由于能夠方便地釋放連接,它減輕了資源需求。然而,從上表看起來使用本地記錄集對提高效率顯然沒有什么幫助。這或許是因為使用本地記錄集時,不管程序設置的是什么,游標總是變成靜態類型。

       第6個規則如下:

    l除非確實要求記錄集本地化,否則應避免使用。
    十、用哪種方法引用記錄集字段值效率最高?

       10.1 測試

       至此為止我們一直通過名字引用記錄集中的字段值。由于這種方法要求每次都必須尋找相應的字段,它的效率并不高。為證明這一點,下面這個測試中我們通過字段在集合中的索引引用它的值(ADO__08.asp):

    'write data
    Do While Not objRS.EOF
    Response.Write( _
    "< TR >" & _
    "< TD >" & objRS(0) & "< /TD >" & _
    "< TD >" & objRS(1) & "< /TD >" & _
    "< TD >" & objRS(2) & "< /TD >" & _
    "< TD >" & objRS(3) & "< /TD >" & _
    "< TD >" & objRS(4) & "< /TD >" & _
    "< TD >" & objRS(5) & "< /TD >" & _
    "< TD >" & objRS(6) & "< /TD >" & _
    "< /TR > " _
    )
    objRS.MoveNext
    Loop


       和預期的一樣,頁面開銷也有小小的變化(這或許是因為代碼略有減少)。然而,這種方法在顯示時間上的改善是相當明顯的。

       在下一個測試中,我們把所有的字段分別綁定到變量(ADO__09.asp):

    If objRS.EOF Then
    Response.Write("No Records Found")
    Else
    'write headings
    ...
    Dim fld0
    Dim fld1
    Dim fld2
    Dim fld3
    Dim fld4
    Dim fld5
    Dim fld6
    Set fld0 = objRS(0)
    Set fld1 = objRS(1)
    Set fld2 = objRS(2)
    Set fld3 = objRS(3)
    Set fld4 = objRS(4)
    Set fld5 = objRS(5)
    Set fld6 = objRS(6)
    'write data
    Do While Not objRS.EOF
    Response.Write( _
    "< TR >" & _
    "< TD >" & fld0 & "< /TD >" & _
    "< TD >" & fld1 & "< /TD >" & _
    "< TD >" & fld2 & "< /TD >" & _
    "< TD >" & fld3 & "< /TD >" & _
    "< TD >" & fld4 & "< /TD >" & _
    "< TD >" & fld5 & "< /TD >" & _
    "< TD >" & fld6 & "< /TD >" & _
    "< /TR >" _
    )
    objRS.MoveNext
    Loop
    Set fld0 = Nothing
    Set fld1 = Nothing
    Set fld2 = Nothing
    Set fld3 = Nothing
    Set fld4 = Nothing
    Set fld5 = Nothing
    Set fld6 = Nothing
    Response.Write("< /TABLE >")
    End If

       這是目前為止最好的記錄。請注意單個記錄的顯示時間已經降低到0.45毫秒以下。

       上述腳本都要求對結果記錄集的構造有所了解。例如,我們在列標題中直接使用了字段名字,單獨地引用各個字段值。下面這個測試中,不僅字段數據通過遍歷字段集合得到,而且字段標題也用同樣的方式得到,這是一種更為動態的方案(ADO__10.asp)。

    If objRS.EOF Then
    Response.Write("No Records Found")
    Else
    'write headings Response.Write("< TABLE BORDER=1 >< TR >")
    For Each objFld in objRS.Fields
    Response.Write("< TH >" & objFld.name & "< /TH >")
    Next
    Response.Write("< /TR >")
    'write data
    Do While Not objRS.EOF
    Response.Write("< TR >")
    For Each objFld in objRS.Fields
    ? Response.Write("< TD >" & objFld.value & "< /TD >")
    Next
    Response.Write("< /TR >")
    objRS.MoveNext
    Loop
    Response.Write("< /TABLE >")
    End If

       可以看到,代碼性能有所下降,但它仍舊要比ADO__07.asp要快。

       下一個測試示例是前面兩個方法的折衷。我們將繼續保持動態特征,同時通過在動態分配的數組中保存字段引用提高性能:

    If objRS.EOF Then
    Response.Write("No Records Found")
    Else
    Dim fldCount
    fldCount = objRS.Fields.Count
    Dim fld()
    ReDim fld(fldCount)
    Dim i
    For i = 0 to fldCount-1
    Set fld(i) = objRS(i)
    Next

    'write headings
    Response.Write("< TABLE BORDER=1 >< TR >") For i = 0 to fldCount-1
    Response.Write("< TH >" & fld(i).name & "< /TH >")
    Next
    Response.Write("< /TR >")
    'write data
    Do While Not objRS.EOF
    Response.Write("< TR >")
    For i = 0 to fldCount-1
    Response.Write("< TD >" & fld(i) & "< /TD >")
    Next
    Response.Write("< /TR >")
    objRS.MoveNext
    Loop
    For i = 0 to fldCount-1
    Set fld(i) = Nothing
    Next
    Response.Write("< /TABLE >")
    End If


       雖然還不能超過以前最好的成績,但它比開頭的幾個示例要快,同時它具有動態地處理任何記錄集這一優點。

       與前面的測試代碼相比,下面的測試代碼有了根本性的改動。它使用記錄集對象的GetRows方法填充數組以供循環訪問數據,而不是直接訪問記錄集本身。注意在調用GetRows之后立即把Recordset設置成了Nothing,也就是盡快地釋放了系統資源。另外,請注意數組的第一維代表字段,第二維代表行(ADO__12.asp)。

    If objRS.EOF Then
    Response.Write("No Records Found")
    objRS.Close
    Set objRS = Nothing
    Else
    'write headings
    ...

    'set array
    Dim arrRS
    arrRS = objRS.GetRows
    'close recordset early
    objRS.Close
    Set objRS = Nothing

    'write data
    Dim numRows
    Dim numFlds
    Dim row
    Dim fld
    numFlds = Ubound(arrRS, 1)
    numRows = Ubound(arrRS, 2)
    For row= 0 to numRows
    Response.Write("< TR >")
    For fld = 0 to numFlds
    Response.Write("< TD >" & arrRS(fld, row) & "< /TD >")
    Next
    Response.Write("< /TR >")
    Next

    Response.Write("< /TABLE >")
    End If

       使用GetRows方法時,整個記錄集都被提取到了數組。雖然記錄集極端龐大時可能產生資源問題,但是用循環訪問數據的速度確實更快了,這是由于取消了MoveNext和檢查EOF之類的函數調用。

       速度是要付出代價的,現在記錄集的元數據已經丟失了。為解決這個問題,我們可以在調用GetRows之前從記錄集對象提取標題信息;此外,數據類型和其他信息也可以預先提取。另外還要注意的是,測試中性能上的優勢只有在記錄集較大的時候才會出現。

       這一組的最后一個測試中,我們使用了記錄集的GetString方法。GetString方法將整個記錄集提取成為一個大的字符串,并允許指定分隔符(ADO__13.asp):

    If objRS.EOF Then
    Response.Write("No Records Found")
    objRS.Close
    Set objRS = Nothing
    Else
    'write headings
    ...
    'set array
    Dim strTable
    strTable = objRS.GetString (2, , "</TD><TD>", "</TD></TR><TR><TD>")
    'close recordset early
    objRS.Close
    Set objRS = Nothing
    Response.Write(strTable & "</TD></TR></TABLE>")
    End If

       雖然這種方法在速度上的好處非常明顯,但它只適用于最簡單的操作,根本無法適應稍微復雜的數據操作要求。

    延伸閱讀

    文章來源于領測軟件測試網 http://www.kjueaiud.com/

    TAG: asp 性能測試


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備2023014753號-2
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>