原文作者:Ambily.raj
Visual Studio是可以用於性能測試的工具之一。Visual Studio Test版或Visual Studio 2010旗艦版為自動化測試提供了支持。本文介紹Visual Studio的Web測試功能。
介紹
對於一個多用戶的應用程序,性能是非常重要的。性能不僅是執行的速度,它包括負載和並發方面。性能測試是對以下問題的回答:
- 我們如何確保我們的新的應用程序將支持預期的用戶負載?
- 如何避免在實際負載條件下會出現的問題?
- 如何確定響應時間?
- 如何規划服務器的容量?
Visual Studio是可以用於性能測試的工具之一。Visual Studio Test版或Visual Studio 2010旗艦版為自動化測試提供了支持。
這將是第一部分的一系列文章。
-
Part I: Web測試和配置
-
Part II:負載測試,RIG和負載測試術語。
-
Part III:性能計數器,負載測試結果分析。
VS 2010測試類型
Visual Studio支持多種可用於執行自動化測試的測試類型。圖1顯示了VSTS 2010中的主要測試類型。

Basic Unit Test,Unit Test和Unit Test Wizard幫助創建新的單元測試的類文件。這將有助於開發人員和測試人員執行單元測試。
Coded UI test用於從手工測試中錄制UI活動。
Database Unit Test用於測試存儲過程和函數。
Generic Test用於把一個可執行文件封裝成一個測試方法。您可以把一個可執行文件封裝成一個測試方法並把它包含在自動化測試中。
Ordered test是在一個特定的順序中執行多個測試腳本。
Web Performance Test用於錄制URL並生成用於性能測試的代碼。
Web測試
Web Performance Test或者Web test,可以執行Web應用程序測試。我們將通過選擇從測試項目模板創建一個測試項目。

一旦你創建好測試項目,右鍵單擊該項目,並添加新的項。選擇Web Performance Test,這將在Internet Explorer中打開錄制器,並開始錄制URL和相關參數。
錄制
下圖顯示了Web測試錄制器,錄制在google上的操作。

在這個例子中,我們記錄到谷歌的搜索功能。一旦錄制結束,在Web測試錄制器中使用“停止”按鈕停止錄制。這將把錄制的URL生成一個Web測試,並添加動態的相關性。
相關性(Correlation)
什么是相關性,簡而言之就是上一次Web請求的響應和下次請求之間的關聯。
例如,當你登錄網站時,它會生成一個用於跟蹤會話的SID。登錄后,這SID被傳遞給了客戶端。隨着下一個請求,存儲的SID將被發送到服務器。當您使用Web測試錄制這一操作時,它會記錄這個值並硬編碼保存。但是,下一次運行時SID會有所不同。
為了避免這樣的情況,需要把登錄請求的響應中的SID值關聯為下次請求時的參數。 首先,我們將提取的SID值,並儲存為一個上下文參數,它將被作為參數傳遞給下一個請求。
上下文參數(Context Parameter)
上下文參數,它就像全局變量一樣。如果你想在所有的URL中使用同一個參數,那么把它聲明為上下文參數。
例如,我們需要在多種環境中運行該腳本。不需要為每種環境單獨錄制一遍,而是定義一個名為’WebServer’的上下文參數,並在每個需要用到的URL中使用它。上下文參數需要在兩層大括號中引用,如{{Webserver}}。把所有的URL修改為使用相同的上下文參數。當你想在另一個環境中運行該腳本,修改上下文參數的值,所有的URL將自動更新。

Query String作為URL的一部分被記錄下來。

在測試環境中,Query String輸入的值會有所不同,這取決於測試類型:正向測試,反向測試,邊界測試等。為了傳遞多個不同值的參數,我們需要做參數化。
參數化(Parameterization)
為了參數化參數(arguments),需要添加數據源用於選取參數值。右鍵單擊Web test - >選擇“Add Data Source”選項。

選擇數據源的類型。數據源可以是數據庫,如SQL Server,Oracle和Excel數據,也可以是CSV或XML文件。

選擇數據文件或數據庫,表中包含輸入數據。數據預覽將顯示在向導中。

點擊Query String來查看Query String的屬性。更改該值使用數據源映射如下。

數據源綁定將作為Query String的值顯示

提取規則
提取規則被用於從一個請求的響應中提取的數據。我們有以下提取選項:提取表單字段,提取HTTP頭等,提取的值可以用來作為下一個Web請求的一部分,或可用於任何商業決策。
在下面的例子中,我使用”提取文本“選項,提取從服務器傳遞來的一個id。通過分析HTML輸出,我們在規則屬性的“Starts With”和“Ends With”中填入對應的匹配值。這個HTML響應將作為最終窗口的一部分顯示(不久將討論)。

驗證規則
驗證規則用於確保你處於正確的頁面中。例如登錄后,你可能會期待頁面中包含”SignOut”文本。以下驗證規則,驗證當前的響應中是否包含“SignOut”文本。
我們可以使用以下驗證規則屬性中的任何選項形成驗證規則。Visual Studio 2010和2008會為錄制的測試自動添加響應URL驗證。

事務(Transaction)
事務是執行一個特定操作所必需的,一組操作或來回應答的集合。例如,購買一本書的過程中包括的步驟:選擇一本書,加入購物車,檢查和付款。
定義事務將有助於分析結果。通常情況下,響應時間,響應字節等信息,將分別為每個URL顯示。一旦你定義了事務,響應時間和其他衡量數據,將在事務級別顯示。

運行測試
當你運行測試,你將看到如下屏幕,在這里你可以看到每個URL的狀態,結果在web瀏覽器中是如何顯示的,哪些參數作為請求的一部分傳遞,HTML響應,上下文參數和其他一些細節。

這是單次運行的情況。如果你想使用參數化來運行多次測試,請單擊屏幕頂部的“Edit run Settings“選項。

在這里,您可以指定需要運行測試的次數。每次運行都會從參數數據源中選擇一個記錄來運行測試。運行次數的同時,我們可以指定瀏覽器的類型,這樣就可以模擬網站在不同的瀏覽器中的展現。
設置運行設置后,在屏幕頂部選擇”Click here to run again“選項。
生成代碼
生成代碼選項允許您根據腳本創建對應的代碼。

這將生成一份和 web test對應的C#代碼,同時為它創建一個單獨的測試。我們可以修改代碼,而不會影響原有的web test,反之亦然。
我們可以使用C#的功能,來自定義這種編碼的Web測試。可以使用循環迭代一個操作或用ADO.NET連接到數據庫為請求提取一些數據,強制執行思考時間(在PartII中討論)和處理WCF Services。
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30128.1
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace GoogleTestProject
{
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.WebTesting;
using Microsoft.VisualStudio.TestTools.WebTesting.Rules;
public class WebTest1Coded : WebTest
{
public WebTest1Coded()
{
this.Context.Add("WebServer", "www.google.co.in");
this.PreAuthenticate = true;
}
public override IEnumerator<WebTestRequest> GetRequestEnumerator()
{
// Initialize validation rules that apply to all requests in the WebTest
if ((this.Context.ValidationLevel >= Microsoft.VisualStudio.TestTools.WebTesting.ValidationLevel.Low))
{
ValidateResponseUrl validationRule1 = new ValidateResponseUrl();
this.ValidateResponse += new EventHandler<ValidationEventArgs>(validationRule1.Validate);
}
if ((this.Context.ValidationLevel >= Microsoft.VisualStudio.TestTools.WebTesting.ValidationLevel.Low))
{
ValidationRuleResponseTimeGoal validationRule2 = new ValidationRuleResponseTimeGoal();
validationRule2.Tolerance = 0D;
this.ValidateResponseOnPageComplete += new EventHandler<ValidationEventArgs>(validationRule2.Validate);
}
WebTestRequest request1 = new WebTestRequest("http://www.google.com/");
request1.ThinkTime = 1;
request1.ExpectedResponseUrl = "http://www.google.co.in/";
ExtractHiddenFields extractionRule1 = new ExtractHiddenFields();
extractionRule1.Required = true;
extractionRule1.HtmlDecode = true;
extractionRule1.ContextParameterName = "1";
request1.ExtractValues += new EventHandler<ExtractionEventArgs>(extractionRule1.Extract);
yield return request1;
request1 = null;
WebTestRequest request2 = new WebTestRequest("http://clients1.google.co.in/generate_204");
yield return request2;
request2 = null;
WebTestRequest request3 = new WebTestRequest("http://www.google.co.in/csi");
request3.QueryStringParameters.Add("v", "3", false, false);
request3.QueryStringParameters.Add("s", "webhp", false, false);
request3.QueryStringParameters.Add("action", "", false, false);
request3.QueryStringParameters.Add("e", "17259,18168,23730,24808", false, false);
request3.QueryStringParameters.Add("ei", "gV_yS7vIKYqC7QPFmZznCw", false, false);
request3.QueryStringParameters.Add("expi", "17259,18168,23730,24808", false, false);
request3.QueryStringParameters.Add("imc", "1", false, false);
request3.QueryStringParameters.Add("imn", "1", false, false);
request3.QueryStringParameters.Add("imp", "1", false, false);
request3.QueryStringParameters.Add("rt", "prt.77,xjsls.102,ol.1085,iml.353,xjses.1817,xjs.1849", false, false);
yield return request3;
request3 = null;
WebTestRequest request4 = new WebTestRequest("http://clients1.google.co.in/complete/search");
request4.QueryStringParameters.Add("hl", this.Context["$HIDDEN1.hl"].ToString(), false, false);
request4.QueryStringParameters.Add("client", "hp", false, false);
request4.QueryStringParameters.Add("expIds", "17259,18168,23730,24808", false, false);
request4.QueryStringParameters.Add("q", "as", false, false);
request4.QueryStringParameters.Add("cp", "2", false, false);
yield return request4;
request4 = null;
WebTestRequest request5 = new WebTestRequest("http://clients1.google.co.in/complete/search");
request5.QueryStringParameters.Add("hl", this.Context["$HIDDEN1.hl"].ToString(), false, false);
request5.QueryStringParameters.Add("client", "hp", false, false);
request5.QueryStringParameters.Add("expIds", "17259,18168,23730,24808", false, false);
request5.QueryStringParameters.Add("q", "asp", false, false);
request5.QueryStringParameters.Add("cp", "3", false, false);
yield return request5;
request5 = null;
WebTestRequest request6 = new WebTestRequest("http://clients1.google.co.in/complete/search");
request6.QueryStringParameters.Add("hl", this.Context["$HIDDEN1.hl"].ToString(), false, false);
request6.QueryStringParameters.Add("client", "hp", false, false);
request6.QueryStringParameters.Add("expIds", "17259,18168,23730,24808", false, false);
request6.QueryStringParameters.Add("q", "asp.", false, false);
request6.QueryStringParameters.Add("cp", "4", false, false);
yield return request6;
request6 = null;
WebTestRequest request7 = new WebTestRequest("http://clients1.google.co.in/complete/search");
request7.QueryStringParameters.Add("hl", this.Context["$HIDDEN1.hl"].ToString(), false, false);
request7.QueryStringParameters.Add("client", "hp", false, false);
request7.QueryStringParameters.Add("expIds", "17259,18168,23730,24808", false, false);
request7.QueryStringParameters.Add("q", "asp.n", false, false);
request7.QueryStringParameters.Add("cp", "5", false, false);
yield return request7;
request7 = null;
WebTestRequest request8 = new WebTestRequest(("http://"
+ (this.Context["WebServer"].ToString() + "/")));
request8.ExpectedResponseUrl = "http://www.google.co.in/#hl=en&source=hp&q=asp.net&rlz=1R2ADFA_enIN375&aq=f&aqi=&" +
"aql=&oq=&gs_rfai=&fp=4a7b17d2fd7e8e7";
yield return request8;
request8 = null;
WebTestRequest request9 = new WebTestRequest("http://clients1.google.co.in/complete/search");
request9.QueryStringParameters.Add("hl", this.Context["$HIDDEN1.hl"].ToString(), false, false);
request9.QueryStringParameters.Add("client", "hp", false, false);
request9.QueryStringParameters.Add("expIds", "17259,18168,23730,24808", false, false);
request9.QueryStringParameters.Add("q", "asp.net", false, false);
request9.QueryStringParameters.Add("cp", "7", false, false);
yield return request9;
request9 = null;
WebTestRequest request10 = new WebTestRequest("http://www.google.co.in/search");
request10.ThinkTime = 1;
request10.QueryStringParameters.Add("hl", this.Context["$HIDDEN1.hl"].ToString(), false, false);
request10.QueryStringParameters.Add("source", this.Context["$HIDDEN1.source"].ToString(), false, false);
request10.QueryStringParameters.Add("q", "asp.net", false, false);
request10.QueryStringParameters.Add("rlz", "1R2ADFA_enIN375", false, false);
request10.QueryStringParameters.Add("aq", "f", false, false);
request10.QueryStringParameters.Add("aqi", "", false, false);
request10.QueryStringParameters.Add("aql", "", false, false);
request10.QueryStringParameters.Add("oq", "", false, false);
request10.QueryStringParameters.Add("gs_rfai", "", false, false);
request10.QueryStringParameters.Add("fp", "4a7b17d2fd7e8e7", false, false);
yield return request10;
request10 = null;
WebTestRequest request11 = new WebTestRequest("http://www.google.co.in/csi");
request11.QueryStringParameters.Add("v", "3", false, false);
request11.QueryStringParameters.Add("s", "web", false, false);
request11.QueryStringParameters.Add("action", "", false, false);
request11.QueryStringParameters.Add("ei", "hl_yS7TeHYTHrAfgy7jKDQ", false, false);
request11.QueryStringParameters.Add("e", "17259,18168,23730,24808", false, false);
request11.QueryStringParameters.Add("cp", "false", false, false);
request11.QueryStringParameters.Add("imp", "0", false, false);
request11.QueryStringParameters.Add("imn", "1", false, false);
request11.QueryStringParameters.Add("rt", "prt.586,pprt.599,ol.599,jsrt.565,iml.599", false, false);
yield return request11;
request11 = null;
WebTestRequest request12 = new WebTestRequest("http://clients1.google.co.in/generate_204");
yield return request12;
request12 = null;
}
}
}
總結
Web Performance Test可以記錄網站鏈接跳轉並生成代碼。我們可以使用Web測試腳本或從其生成的代碼作為性能測試的輸入。自定義的測試可以使我們做到:
參數化 - 使用戶輸入動態化
關聯性 - 提取服務器產生的數據,用於后續請求。
PartII中,我們將探討負載測試,PartIII是對性能測試結果進行分析和理解的主要性能計數器。
本文由知平軟件的劉斌華翻譯,轉載請注明出處。原文地址:http://www.dotnetfunda.com/articles/article901-web-performance-test-using-visual-studio-part-i.aspx
知平軟件致力於移動平台自動化測試技術的研究,我們希望通過向社區貢獻知識和開源項目,來促進行業和自身的發展。
