The following sample shows how to model the common scenario where a user logs on once to a Web site and performs a number of tests.  

 

In the sample, the logon action is definded by a set of login requests. Each Web test contains the same set of login requests plus its own non-login requests.

 

A “new user” as defined by “Percentage of New Users” under the Load test scenario property always executes Login once and one iteration of a Web test (the non-login section)  from the Test Mix. A “return user” always executes Logon once and a random number of Web tests (the non-login sections) from the Test Mix.

 

Modeling can be achieved by using plug-ins or coded web tests .

==============================================================================

A. To do this using plug-ins:

  1. Create a new test project.
  2. Add WebRequestPlugin.cs, WebTestPlugin.cs, LoadTestPlugin.cs, VUserInfo.cs and WebTestUserMonitor.cs to the project.
  3. Create the web tests. Each Web test contains the same set of login request(s). i.e

            WebTest1

                        login requests

                        non-login requests

 

            WebTest2

                        login requests

                        non-login requests

 

            WebTest3

                        login requests

                        non-login requests

 

            Suffix the set of login requests. i.e,

 

If the original set of login requests are

 

http://server/loginRequest1.aspx

http://server/loginRequest2.aspx

http://server/loginRequest3.aspx

...

http://server/loginRequestN.aspx

 

Login requests after appending suffixes will be

 

http://server/loginRequest1.aspxLoginRequestFirst

http://server/loginRequest2.aspxLoginRequest

http://server/loginRequest3.aspxLoginRequest

...

http://server/loginRequestN.aspxLoginRequestLast

 

  1. Add the Web test and request plug-ins to all of your Web tests
  2. Add the web tests to a load test scenario
  3. Optional. Add the load test plug-in to the load test if you want to output the number of login test executed. You can generate your own report by modifying the Stop() in WebTestUserMonitor class.

 

WebTestPlugin.cs

 

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.VisualStudio.TestTools.WebTesting;

 

namespace TestMixPlugins

{

    public class TestPlugin : WebTestPlugin

    {

        public override void PreWebTest(object sender, PreWebTestEventArgs e)

        {

            WebTestUserMonitor.Instance.PreWebTest(sender, e);

        }

 

        public override void PostWebTest(object sender, PostWebTestEventArgs e)

        {

            WebTestUserMonitor.Instance.PostWebTest(sender, e);

        }

    }

}

 

WebRequestPlugin.cs

 

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.VisualStudio.TestTools.WebTesting;

 

namespace TestMixPlugins

{

    public class RequestPlugin : WebTestRequestPlugin

    {

        public override void PreRequest(object sender, PreRequestEventArgs e)

        {

            WebTestUserMonitor.Instance.login_PreRequest(sender, e);

        }

 

        public override void PostRequest(object sender, PostRequestEventArgs e)

        {

            bool login = e.WebTest.Context.ContainsKey(WebTestUserMonitor.LOGIN) ? (bool)e.WebTest.Context[WebTestUserMonitor.LOGIN] : true;

            bool isLastLoginRequest = e.WebTest.Context.ContainsKey(WebTestUserMonitor.IS_LAST_LOGIN_REQUEST) ? (bool)e.WebTest.Context[WebTestUserMonitor.IS_LAST_LOGIN_REQUEST] : false;

 

            // if login = true && this is the last login request

            if (login && isLastLoginRequest)

            {

                WebTestUserMonitor.Instance.login_PostRequest(sender, e);

                return;

            }          

        }

    }

}

 

LoadTestPlugin.cs

 

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.VisualStudio.TestTools.LoadTesting;

 

namespace TestMixPlugins

{

    public class LoadTestPlugin : ILoadTestPlugin 

    {

        public void Initialize(LoadTest loadTest)

        {

            m_loadTest = loadTest;

            m_loadTest.LoadTestStarting += new EventHandler(m_loadTest_LoadTestStarting);

            m_loadTest.LoadTestFinished += new EventHandler(m_loadTest_LoadTestFinished);

        }

 

        void m_loadTest_LoadTestStarting(object sender, EventArgs e)

        {

            WebTestUserMonitor.Instance.Start();

        }

 

        void m_loadTest_LoadTestFinished(object sender, EventArgs e)

        {

            WebTestUserMonitor.Instance.Stop();

        }

 

        private static LoadTest m_loadTest;

    }

}

 

 

VUserInfo.cs

using System;

using System.Collections.Generic;

using System.Text;

 

namespace TestProject1

{

    class VUserInfo

    {

        // This class stores a vuser's information during test execution

        public VUserInfo(int userId)

        {

            m_userId = userId;

            m_numTestExecuted = 0;

            m_loginContext = new Dictionary<string, object>();

            m_testList = new List<string>();

        }

 

        public int UserId

        {

            get { return m_userId; }

        }

 

        // Number of tests that have been completed by the user

        public int NumTestExecuted

        {

            get { return m_numTestExecuted; }

            set { m_numTestExecuted = value; }

        }

 

        // Web test context needed to issue non-login requests for a return user

        public Dictionary<string, object> LoginContext

        {

            get { return m_loginContext; }

            set { m_loginContext = value; }

        }

 

        public List<string> TestList

        {

            get { return m_testList; }

        }

 

        private int m_userId;

        private int m_numTestExecuted;

        private Dictionary<string, object> m_loginContext;

        private List<string> m_testList;

    }

}

    

WebTestUserMonitor.cs

 

using System;

using System.IO;

using System.Text;

using System.Collections.Generic;

using Microsoft.VisualStudio.TestTools.WebTesting;

 

namespace TestMixPlugins

{

    public class WebTestUserMonitor

    {

        public static WebTestUserMonitor Instance

        {

            get { return s_instance; }

        }

 

        public void PreWebTest(object sender, PreWebTestEventArgs e)

        {

            int userId = e.WebTest.Context.WebTestUserId;

            bool isNewUser = e.WebTest.Context.IsNewUser;

            bool login = false;

 

            lock (s_usersLock)

            {

                if (!s_users.ContainsKey(userId))

                {

                    s_users.Add(userId, new VUserInfo(userId));

                }

 

                int numTestExecuted = s_users[userId].NumTestExecuted;

 

                // if this is a new user, enable login

                // if this is a returning user, add the login context needed for the test

                if (isNewUser || numTestExecuted == 0)

                {

                    login = true;

                }

                else

                {

                    e.WebTest.Context.Add(LOGIN_CONTEXT, s_users[userId].LoginContext);

                }

            }

 

            e.WebTest.Context.Add(LOGIN, login);

        }

 

        public void PostWebTest(object sender, PostWebTestEventArgs e)

        {

            int userId = e.WebTest.Context.WebTestUserId;

            string testName = e.WebTest.Name;

 

            lock (s_usersLock)

            {

                s_users[userId].NumTestExecuted++;

                s_users[userId].TestList.Add(testName);

 

                if (e.WebTest.Context.IsNewUser)

                {

                    s_users.Remove(userId);

                }

                else

                {

                    // save the login context for future usage

                    if ((bool)e.WebTest.Context[LOGIN])

                    {

                        s_users[userId].LoginContext = (Dictionary<string, object>)e.WebTest.Context[LOGIN_CONTEXT];

                    }

                }

 

                bool login = e.WebTest.Context.ContainsKey(LOGIN) ? (bool)e.WebTest.Context[LOGIN] : true;

                if (login)

                {

                    s_numOfLoginTest++;

                }

            }

        }

 

        public void login_PreRequest(object sender, PreRequestEventArgs e)

        {

            bool login = e.WebTest.Context.ContainsKey(LOGIN) ? (bool)e.WebTest.Context[LOGIN] : true;

            bool isFirstLoginRequest = true;

            bool isLastLoginRequest = true;

            bool isLoginRequest = true;

 

            isFirstLoginRequest = e.Request.Url.Contains("LoginRequestFirst");

            isLastLoginRequest = e.Request.Url.Contains("LoginRequestLast");

            isLoginRequest = e.Request.Url.Contains("LoginRequest");

 

            // remove the suffix from the request

            if (isLoginRequest)

            {

                int endPos = e.Request.Url.IndexOf("LoginRequest");

                if (endPos > 0)

                {

                    e.Request.Url = e.Request.Url.Substring(0, endPos);

                }

            }

 

            if (login)

            {

                if (isFirstLoginRequest)

                {

                    // copy the context before the first login request is issued

                    KeyValuePair<string, object>[] contextBeforeLogin = new KeyValuePair<string, object>[e.WebTest.Context.Count];

                    e.WebTest.Context.CopyTo(contextBeforeLogin, 0);

                    e.WebTest.Context.Add(CONTEXT_BEFORE_LOGIN, contextBeforeLogin);

                }

 

                if (isLastLoginRequest)

                {

                    e.WebTest.Context.Add(IS_LAST_LOGIN_REQUEST, true);

                }

 

                return;

            }

 

            // login is not needed, skip the login requests

            if (isLoginRequest)

            {

                e.Instruction = WebTestExecutionInstruction.Skip;

            }

 

            if (isFirstLoginRequest)

            {

                // Copy the Login context required for the rest of the test

                int count = ((Dictionary<string, object>)e.WebTest.Context[LOGIN_CONTEXT]).Count;

                KeyValuePair<string, object>[] loginContext = new KeyValuePair<string, object>[count];

                ((ICollection<KeyValuePair<string, object>>)e.WebTest.Context[LOGIN_CONTEXT]).CopyTo(loginContext, 0);

                System.Collections.IEnumerator ienum = loginContext.GetEnumerator();

 

                while (ienum.MoveNext())

                {

                    KeyValuePair<string, object> keyValuePair = (KeyValuePair<string, object>)ienum.Current;

                    e.WebTest.Context.Add(keyValuePair.Key, keyValuePair.Value);

                }

            }

        }

 

        public void login_PostRequest(object sender, PostRequestEventArgs e)

        {

            // this is the last login request

            Dictionary<string, object> contextBeforeLogin = new Dictionary<string, object>();

            Dictionary<string, object> contextChangedByLogin = new Dictionary<string, object>();

 

            System.Collections.IEnumerator ienum = ((KeyValuePair<string, object>[])e.WebTest.Context[CONTEXT_BEFORE_LOGIN]).GetEnumerator();

            while (ienum.MoveNext())

            {

                KeyValuePair<string, object> keyValuePair = (KeyValuePair<string, object>)ienum.Current;

                contextBeforeLogin.Add(keyValuePair.Key, keyValuePair.Value);

            }

 

            // compare the contexts before and after login, get the context changed by the login

            foreach (KeyValuePair<string, object> keyValuePair in e.WebTest.Context)

            {

                string key = keyValuePair.Key;

                object value1 = keyValuePair.Value;

 

                if (contextBeforeLogin.ContainsKey(key))

                {

                    object value2 = contextBeforeLogin[key];

                    if (value1.ToString().ToUpper().CompareTo(value2.ToString().ToUpper()) != 0)

                    {

                        contextChangedByLogin.Add(key, value1);

                    }

                }

                else

                {

                    contextChangedByLogin.Add(key, value1);

                }

            }

 

            e.WebTest.Context.Add(LOGIN_CONTEXT, contextChangedByLogin);

            e.WebTest.Context.Remove(IS_LAST_LOGIN_REQUEST);

        }

 

        public void Start()

        {

            FileInfo file = new FileInfo(m_logFile);

            if (file.Exists)

            {

                file.Delete();

            }

        }

 

        public void Stop()

        {

            lock (s_usersLock)

            {

                File.AppendAllText(m_logFile, "Number of login tests executed: " + s_numOfLoginTest.ToString());

            }

        }

 

        public static readonly string LOGIN = "Login";

        public static readonly string IS_LAST_LOGIN_REQUEST = "IsLastLoginRequest";

        private const string CONTEXT_BEFORE_LOGIN = "ContextBeforeLogin";

        private const string LOGIN_CONTEXT = "LoginContext";

        private readonly string m_logFile = "d:\\result.txt";

        private static object s_usersLock = new object();

        private static int s_numOfLoginTest = 0;

        private static WebTestUserMonitor s_instance = new WebTestUserMonitor();

        private static Dictionary<int, VUserInfo> s_users = new Dictionary<int, VUserInfo>();

    }

}

 

=====================================================================

B. To do this using coded web tests:

  1. Create a new test project.
  2. Add VUserInfo.cs and WebTestUserMonitor.cs to the project.
  3. Create the web tests. Each web test should include the same set of login request(s).
  4. Generate coded Web tests from the existing ones.
  5. Modify the coded Web tests as suggested in the following code sample.
  6. Add the coded Web tests to a load test.

   

WebTestUserMonitor.cs

using System;

using System.IO;

using System.Text;

using System.Collections.Generic;

using Microsoft.VisualStudio.TestTools.WebTesting;

 

namespace TestProject1

{

    public class WebTestUserMonitor

    {

        public WebTestUserMonitor()

        {

        }

 

        public static WebTestUserMonitor Instance

        {

            get { return s_instance; }

        }

 

        public void PreWebTest(object sender, PreWebTestEventArgs e)

        {

            int userId = e.WebTest.Context.WebTestUserId;

            // Is this a new user

            bool isNewUser = e.WebTest.Context.IsNewUser;

            bool login = false;

 

            lock (s_usersLock)

            {

                if (!s_users.ContainsKey(userId))

                {

                    s_users.Add(userId, new VUserInfo(userId));

                }

 

                int numTestExecuted = s_users[userId].NumTestExecuted;

 

                // If this is a new user, enable login

                // If this is a return user, add the login context needed for the test

                if (isNewUser || numTestExecuted == 0)

                {

                    login = true;

                }

                else

                {

                    e.WebTest.Context.Add(LOGIN_CONTEXT, s_users[userId].LoginContext);

                }

            }

 

            e.WebTest.Context.Add(LOGIN, login);

        }

 

        public void PostWebTest(object sender, PostWebTestEventArgs e)

        {

            int userId = e.WebTest.Context.WebTestUserId;

            string testName = e.WebTest.Name;

 

            lock (s_usersLock)

            {

                s_users[userId].NumTestExecuted++;

                s_users[userId].TestList.Add(testName);

 

                if (e.WebTest.Context.IsNewUser)

                {

                    s_users.Remove(userId);

                }

                else

                {

                    // save the login context for future usage

                    if ((bool)e.WebTest.Context[LOGIN])

                    {

                        s_users[userId].LoginContext = (Dictionary<string, object>)e.WebTest.Context[LOGIN_CONTEXT];

                    }

                }

            }

        }

 

        public static void login_PreRequest(object sender, PreRequestEventArgs e)

        {

            KeyValuePair<string, object>[] contextBeforeLogin =

                          new KeyValuePair<string, object>[e.WebTest.Context.Count];

 

            // Get a copy of the context before the login request is issued

            e.WebTest.Context.CopyTo(contextBeforeLogin, 0);

            e.WebTest.Context.Add(CONTEXT_BEFORE_LOGIN, contextBeforeLogin);

        }

 

        public static void login_PostRequest(object sender, PostRequestEventArgs e)

        {

            Dictionary<string, object> contextBeforeLogin =

                                                 new Dictionary<string, object>();

            Dictionary<string, object> contextChangedByLogin =

                                                 new Dictionary<string, object>();

 

            System.Collections.IEnumerator ienum =  ((KeyValuePair<string,object>[])e.WebTest.Context[CONTEXT_BEFORE_LOGIN]).GetEnumerator();

            while (ienum.MoveNext())

            {

                KeyValuePair<string, object> keyValuePair =

                                           (KeyValuePair<string, object>)ienum.Current;

                contextBeforeLogin.Add(keyValuePair.Key, keyValuePair.Value);

            }

 

            // Compare the contexts before and after login, and

            // get the context changed by the login

            foreach (KeyValuePair<string, object> keyValuePair in e.WebTest.Context)

            {

                string key = keyValuePair.Key;

                object value1 = keyValuePair.Value;

 

                if (contextBeforeLogin.ContainsKey(key))

                {

                    object value2 = contextBeforeLogin[key];

                    if (value1.ToString().ToUpper().CompareTo(value2.ToString().ToUpper()) != 0)

                    {

                        contextChangedByLogin.Add(key, value1);

                    }

                }

                else

                {

                    contextChangedByLogin.Add(key, value1);

                }

            }

 

            e.WebTest.Context.Add(LOGIN_CONTEXT, contextChangedByLogin);

        }

 

        private const string CONTEXT_BEFORE_LOGIN = "ContextBeforeLogin";

        private const string LOGIN_CONTEXT = "LoginContext";

        private const string LOGIN = "Login";

        private static object s_usersLock = new object();

        private static WebTestUserMonitor s_instance = new WebTestUserMonitor();

        private static Dictionary<int, VUserInfo> s_users =

                                               new Dictionary<int, VUserInfo>();

    }

}

 

WebTestCoded.cs

namespace TestProject1

{

    using System;

    using System.Collections.Generic;

    using System.Text;

    using TestMixPlugins;

    using Microsoft.VisualStudio.TestTools.WebTesting;

    using Microsoft.VisualStudio.TestTools.WebTesting.Rules;

 

 

    public class WebTest2Coded : WebTest

    {

        public WebTest2Coded()

        {

            this.PreAuthenticate = true;

 

            //---------------------------------------

            // Modification 1

            //---------------------------------------

            // Add the following two lines to your coded web test

            this.PreWebTest += new EventHandler<PreWebTestEventArgs>(WebTestUserMonitor.Instance.PreWebTest);

            this.PostWebTest += new EventHandler<PostWebTestEventArgs>(WebTestUserMonitor.Instance.PostWebTest);

        }

 

        public override IEnumerator<WebTestRequest> GetRequestEnumerator()

        {

            //---------------------------------------

            // Modification 2 - Login Section

            //---------------------------------------

            bool login = Context.ContainsKey("Login") ? (bool)Context["Login"] : true;

 

            // Incorporate the following if-else block into the login section

            if (login)

            {

 

                WebTestRequest loginRequest = new WebTestRequest("http://server/site/login.aspx");

                ExtractHiddenFields rule1 = new ExtractHiddenFields();

                rule1.ContextParameterName = "1";

                loginRequest.ExtractValues += new EventHandler<ExtractionEventArgs>(rule1.Extract);

               

                // Insert the PreRequest and PostRequst handlers for the login request

                loginRequest.PreRequest += new EventHandler<PreRequestEventArgs>(WebTestUserMonitor.login_PreRequest);

                loginRequest.PostRequest += new EventHandler<PostRequestEventArgs>(WebTestUserMonitor.login_PostRequest);

                yield return loginRequest;

 

            }

            else

            {

                // Copy the Login context required for the test

                int count = ((Dictionary<string, object>)Context["LoginContext"]).Count;

                KeyValuePair<string, object>[] loginContext = new KeyValuePair<string,object>[count];

                ((ICollection<KeyValuePair<string, object>>)Context["LoginContext"]).CopyTo(loginContext, 0);

                System.Collections.IEnumerator ienum = loginContext.GetEnumerator();

 

                while (ienum.MoveNext())

                {

                    KeyValuePair<string, object> keyValuePair = (KeyValuePair<string, object>)ienum.Current;

                    Context.Add(keyValuePair.Key, keyValuePair.Value);

                }

            }

            // End of Modification 2

 

            WebTestRequest request1 = new WebTestRequest("http://server/site/page1.aspx");

            yield return request1;

 

            WebTestRequest request2 = new WebTestRequest("http://server/site/page2.aspx");

            yield return request2;

 

            WebTestRequest request3 = new WebTestRequest("http://server/site/page3.aspx");

            yield return request3;

 

        }

    }

}