A. To do this using plug-ins:
- Create a new test project.
- Add WebRequestPlugin.cs, WebTestPlugin.cs, LoadTestPlugin.cs, VUserInfo.cs and WebTestUserMonitor.cs to the project.
- 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
- Add the Web test and request plug-ins to all of your Web tests
- Add the web tests to a load test scenario
- 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>();
}
}