A significant number of the webtests in out loadtest need to simulate a human tying into a people-picker control. This control waits until the first few letters have been entered and after that calls SharePoint’s client.svc web-service every time the user enters data into the control.

I simulate this with the following logic in webtests:

GET https://...
For Each Character In Targetusers display name:
    POST https://.../_vti_bin/client.svc/ProcessQuery
GET https:/...

As Visual Studio doesn’t contain a plugin that iterates over characters in a string, I wrote my own. This plug-in allows you to choose:

  1. Which input parameter contains the display name to iterate over.
  2. Into which output parameter to place the sub-string.
  3. At which index to start iterating. The 1st iteration of the loop includes all characters upto the starting index. All subsequent iterations add one more letter from the input string into the output string.

Some nice-to-have improvements to this plugin are:

  • Add a configurable delay in milliseconds to each loop. This would be nice as think-times on requests can only be configured in intervals of whole seconds
  • Add an option to automatically clear the output parameter once all iterations have finished

Here is the code for the plug-in:

using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.VisualStudio.TestTools.WebTesting;
using Microsoft.VisualStudio.TestTools.WebTesting.Rules;

namespace LoadTestPlugins
{

    [DisplayNameAttribute("For Each character in context parameter")]
    [DescriptionAttribute("Sequentially copies each character from the source into the destination. You can use this to simulate a user that types a name into a peoplepicker for example")]
    public class ForEachCharacter : ConditionalRule
    {

        #region Methods
        public override void CheckCondition(object sender, ConditionalEventArgs e)
        {
            string Input = e.WebTest.Context[this.InputContextParameterName].ToString();
            string Output;
            try
            {
                Output = e.WebTest.Context[this.OutputContextParameterName].ToString();
            }
            catch (KeyNotFoundException)
            {
                Output = string.Empty;
            }


            //Only do something if the output is not yet complete
            if (Input.Length == Output.Length)
            {
                e.IsMet = false;
                return;
            }
            

            int LengthToCopy;
            if(Output.Length == 0)
            {
                //Copy all characters before the starting index and 1 extra
                LengthToCopy = this.StartIndex + 1;
            }
            else 
            {
                //Copy 1 extra character to the output
                LengthToCopy = Output.Length + 1;
            }

            e.IsMet = true;
            e.WebTest.Context[this.OutputContextParameterName] = Input.Substring(0, LengthToCopy);
            return;
        }
        
        #endregion

        #region Properties
        [Description("Name of context parameter that contains the characters to iterate over"),
        DisplayName("Input Context parameter"), IsContextParameterName(true)]
        public string InputContextParameterName {get; set;}

        [Description("Name of context parameter to store the each successive iteration"),
        DisplayName("Ouput Context parameter"), IsContextParameterName(true)]
        public string OutputContextParameterName { get; set; }

        [Description("The zero-based index to start the iteration from"),
        DisplayName("Start Index")]
        public int StartIndex { get; set; }
        #endregion
    }
}