Web Performance Test LINQ’d Extraction Rule

Posted on May 16, 2010

0


Visual Studio has offered web testing features for some time but then just the other day someone asked me for help in Visual Studio 2010 for what I thought would be easy to do: during a web test (now named a Web Performance Test), extract the default value from an HTML Select element (aka Drop Down List).

The issue was that the ASPX generates a default “selected” item based on geography and they wanted to create tests that would dynamically adapt to the server’s selected defaults on their various forms. So extract the selected item from lists instead of assuming a default during the tests.

Bringing us to the default Extraction Rules dialog only to find that once you find a tag, it only offers access to attributes, not child elements. There’s an opportunity for a generalized Extraction Rule…

But I had maybe 15mins to help out, so no time for a generalized extraction rule today. Thankfully Visual Studio parses HTTP Responses during the test. But for our purpose, it does not quite get you where you want to be, even in code:

public override void Extract(object sender, ExtractionEventArgs e)
{
    foreach (var tag in e.Response.HtmlDocument.GetFilteredHtmlTags("select"))
    {
        tag. // oops, no access to child elements
    }

Given the time constraints (and this was live in front of a client) I did what I’m used to doing:

public override void Extract(object sender, ExtractionEventArgs e)

{
    string body = e.Response.BodyString;
 
    string result = string.Empty;
 
    int ixSelect = body.IndexOf("select");
    int ixNameAttrib = body.IndexOf("name", ixSelect);
    string name = body.Substring(ixNameAttrib + "name".Length + 2,
                                 NameOfTargetedSelectElement.Length);
 
    if (name == NameOfTargetedSelectElement)
    {
        int ixSelected = body.IndexOf("selected", ixNameAttrib);
        int ixValue = body.IndexOf(">", ixSelected) + 1;
        int lenValue = body.IndexOf("<", ixValue) - ixValue;
 
        result = body.Substring(ixValue, lenValue);
 
        e.WebTest.Context.Add(
            this.ContextParameterName,
            result);
 
        e.Success = true;
    }
    else
        e.Success = false;
}

And guess what was the very first feedback: Why not use LINQ? Of course! We are using VS2010 so we can go all out.

Two “catches” to be aware of:

First, I am making the risky assumption that my targeted select tag precedes a series of option tags and that one of those option tags would be marked as the default (attribute selected=”selected”).

Second, notice the line where I create a new List of HtmlTag: that is intentional. If we ask the query result for a .Count() it will return the correct result, but you can only ask it that question once. Oops. So I take the LINQ result, put it in a List, then I am making my enquiries to whether the list (result) adhere to my assumptions (see e.Success expression).

public override void Extract(object sender, ExtractionEventArgs e)
    {
        bool ignoreCase = true;
 
        var results = from tag in
                           e.Response.HtmlDocument
                               .GetFilteredHtmlTags("select", "option")
                      where
                           0 == string.Compare(
                              tag.GetAttributeValueAsString("name"),
                              NameOfTargetedSelectElement, ignoreCase)
                           ||
                           0 == string.Compare(
                              tag.GetAttributeValueAsString("selected"),
                              "selected", ignoreCase)
                      select tag;
 
        var resultsList = new List<HtmlTag>(results);
 
        e.Success = resultsList.Count == 2
                    &&
                    resultsList[0].GetAttributeValueAsString("name")
                        == NameOfTargetedSelectElement
                    &&
                    resultsList[1].Name == "option"
                    &&
                    resultsList[1].GetAttributeValueAsString("selected")
                        == "selected";
 
         string result = resultsList[1].GetAttributeValueAsString("value");
 
         e.WebTest.Context.Add(this.ContextParameterName, result);
    }
Advertisement
Posted in: Programming