Web Performance Test Using Visual Studio- Part I
Visual Studio is one of the tools used for Performance Test. Visual Studio Test edition or Visual Studio 2010 Ultimate provides the support for test automation. This article describes the web test feature available in visual studio.
Introduction
Performance of an application is very important for a multi-user application. Performance is not only the speed of execution; it includes the load and concurrency aspects. Performance Test is an answer for the following questions
-
How can we ensure that our new application will support the expected user load?
-
How to avoid the issues which will arise only in real load conditions?
-
How to find the response time?
-
How to plan the capacity of the servers?
Visual Studio is one of the tools used for Performance Test. Visual Studio Test edition or Visual Studio 2010 Ultimate provides the support for test automation.
This will be the first part of a series of articles.
-
Part I: Web Test and Customization
-
Part II: Load Test, RIG and Load test terminologies.
-
Part III: Performance Counters, Load Test Result Analysis.
VS 2010 Test Types
Visual studio support various test types to perform the test automation. Figure 1 shows the main Test types available in VSTS 2010.
Basic Unit Test, Unit Test and Unit Test Wizard helps in creating new Unit test for a class file. This will be helpful for both developers and testers to perform unit level testing.
Coded UI test is used for recording the UI activities of a manual test.
Database Unit Test used for testing stored procedures and functions.
Generic Test is for wrapping an executable as a test method. You can wrap the executable using generic Test and can include the same in test automation.
Ordered test is for executing multiple test scripts in a particular order.
Web Performance Test used for recording the URLs and generating the code for performance testing.
Web Test
Web Performance Test or Web test allows performing the web application test. We will create a test project by selecting the Test project template.
Once you created the test project right click on the project and add new Item. Select the web performance test, which will open the recorder in an internet explorer and start recording the navigation URLs and associated parameters.
Recording
Following figure shows the Web test recorder, records the Google search operation.
In this example, we are recording the search feature of Google. Once the recording is over, stop recording using the Stop button in Web test recorder. This will generate the recorded URLs as a web test and add dynamic correlations to.
Correlation
Correlation is nothing but linking the response of one web request to the next web request.
For example, when you login to the site it generates a SID for tracking the session. This SID is passed to the client after the login request. Along with the next request, the stored SID will be send to server. When you record this operation using Web test, it records the values and saves as hardcoded value. SID will be different for the next run.
For avoiding such situation, correlate the SID value from the response of the login request to the next request parameters. First we will extract the SID values and save in a context parameter, which will be passed to the next request as a parameter.
Context Parameter
Context Parameters is just like to global variables. If you want to refer one parameter across all URLs, declare the same as Context Parameter.
For example, we need to run the script in multiple environments. Instead of recording the script for each environment separately, define the context parameter as ‘Webserver’ and use the same for URL formation. Context Parameters should be referred inside double curly brackets like {{Webserver}}. All the URLs should be modified using the same context parameter. When you want to run the script in another environment, modify the value of the context parameter, which will automatically take care of the URLs.
The query string we used for searching is recorded as part of the URL recording.
In test environment the input value will differ depends on the positive testing, negative testing, boundary testing, etc. For passing multiple values to the parameters, we will do the parameterization.
Parameterization
For parameterizing the arguments, add the data source from where we can pick the values. Right click on the Web test -> Select Add Data Source option.
Select the type of data source. Data Source can be a Database like SQl Server, Oracle and Excel, or data can be fetched from CSV or XML files too.
Select the Data file or the database and table contains the input data. Preview of the data will be displayed on the wizard.
Click on the query string and move to the properties of the querystring. Change the value using the Data Source mapping as below.
Data source binding will be displayed as the query string value
Extraction Rule
Extraction rules are used for extracting the data from the response of a request. We have the following options for extracting the values; extract the form fields, extract HTTP header, etc. Extracted values can be used as part of the next web request or can be used for making any business decisions.
In following example, I used Extract Text option to extract an id passed from the server. By analyzing the html output of the request, you can form the Starts With and Ends With frames. The HTML response is displayed as part of the result window(will discuss soon).
Validation Rule
Validation rules are to enforce you are in the correct page only. After SignIn or Login In, you may be expecting a page with SignOut text. Following validation rule validates, whether the current response contains the text “SignOut’ or not.
We can form the validation rules using any of the following options. Visual Studio 2010 and 2008 automatically add the Response URL validations to the recorded test.
Transaction
Transactions are a set of operations or round-trips required to perform a particular operation. For example, the process of buying a Book consist of steps for select a Book, Add to cart, Check out and Payment.
Defining transactions will be helpful for analyzing the results. Normally the response time, Response Byte, etc. will be displayed for each URL separately. Once you define the transactions, the response time and all other measures will be displayed for the transaction level.
Run Test
When you run the test, you will get the following screen, where you can see the status of each URL, how the result appear in Web Browser, what are the parameters passed as part of the request, HTML response, context parameters and the details.
This is related to single run. If you want to check the parameterization to want to run the test multiple times, click on the Edit run Settings option displayed on top the screen.
Here, you can specify the number of times the test needs to be run. Each run will pick one record from the Parameter data source and run the test. Along with run count, we can specify the browser types too; which simulates how the site appears in different browser.
After setting the run settings, select the Click here to run again option specified on top of the screen.
Generate Code
Generate code option allows you to create the code corresponding to the script.
This will generate the C# code corresponding to the web test and also create a separate Test itself. We can modify the code project without affecting the web test and vice versa.
We can use the C# capabilities to automate or customize the coded web test. Can use loop for iterating one operation or ADO.Net to connect to database and pull some data for request, enforce think times (will discuss in Part II) and process 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; } } }
Conclusion
Web Performance Test can be used for recording the website navigations and generating the Code. We can use this test or the generated coded test as an input to the performance test. Customization of the test can be done using
Parameterization – makes the user inputs dynamic
Correlation – Extract the Server generated data for subsequent requests.
In second part, we will look into the Load test aspects and on third part of this article series is for analyzing the performance test results and understanding the major performance counters.