When doing UI testing of Win Form with .NET, there is an easy way to automate it. It is reflection in .NET.
There is a tool integrated in VSTS, named Spy++, using it you can get any win form caption in your desk.
Following are the code for UI testing by reflection, key code refered <<.NET Test Automation Recipes: A problem-Solution Approach>>, all codes Copyright by Qijie Xue(v-qixue@microsoft.com)
using System;
using System.Threading;
using System.Reflection;
using System.Windows.Forms;
using System.Text;
namespace WinFC
{
/// <summary>
/// Qijie Xue
/// Writed at 8/13/2011
/// </summary>
public class FormClass
{
static AutoResetEvent are = new AutoResetEvent(false);
const BindingFlags bindFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
#region get, set, invoke methods
/// <summary>
/// Get Form property
/// </summary>
/// <param name="theForm">the form you want to get property</param>
/// <param name="propertyName">the property name of the form</param>
/// <returns>the value for the property of the form</returns>
delegate object getFormPropertyHandler(Form theForm, string propertyName);
public object GetFormPropertyByPropertyName(Form theForm, string propertyName)
{
if (theForm == null)
return null;
if (theForm.InvokeRequired)
{
getFormPropertyHandler phandler = new getFormPropertyHandler(GetFormPropertyByPropertyName);
object result = null;
object[] oparams = new object[] {theForm , propertyName};
result = theForm.Invoke(phandler, oparams );
are.WaitOne();
return result;
}
else
{
object result = null;
Type t = theForm.GetType();
PropertyInfo pi = t.GetProperty(propertyName);
if (pi == null)
{
are.Set();
return null;
}
else
{
result = pi.GetValue(theForm, null);
are.Set();
return result;
}
}
}
/// <summary>
/// Set Form Property
/// </summary>
/// <param name="theForm">the form you want to set property</param>
/// <param name="propertyName">the propery name of form</param>
/// <param name="newValue">the new value of this propery you want to set</param>
delegate void setFormPropertyHandler(Form theForm, string propertyName, object newValue);
public void SetFormPropertyByPropertyName(Form theForm, string propertyName, object newValue)
{
if (theForm == null)
return;
if (theForm.InvokeRequired)
{
setFormPropertyHandler setHandler = new setFormPropertyHandler(SetFormPropertyByPropertyName);
object oparams = new object[] { theForm, propertyName, newValue };
theForm.Invoke(setHandler, oparams);
are.WaitOne();
}
else
{
Type t = theForm.GetType();
PropertyInfo pi = t.GetProperty(propertyName);
if (pi == null)
{
are.Set();
return;
}
else
{
try
{
pi.SetValue(theForm, newValue, null);
}
catch
{
//it's a invalid value for this property
return;
}
finally
{
are.Set();
}
}
}
}
/// <summary>
/// Get Control property
/// </summary>
/// <param name="theForm">the form which the control belongs to</param>
/// <param name="controlName">the control name which you want to get</param>
/// <param name="controlPropertyName">the property name of the control you want to get</param>
/// <returns>the value for the property of the control</returns>
delegate object getControlPropertyHandler(Form theForm, string controlName, string controlPropertyName);
public object GetControlPropertyByPropertyName(Form theForm, string controlName, string controlPropertyName)
{
if (theForm == null)
return null;
if (theForm.InvokeRequired)
{
getControlPropertyHandler getHandler = new getControlPropertyHandler(GetControlPropertyByPropertyName);
object result = null;
object oparams = new object[] {theForm , controlName , controlPropertyName };
result = theForm.Invoke(getHandler, oparams);
are.WaitOne();
return result;
}
else
{
Type tForm = theForm.GetType();
FieldInfo fi = tForm.GetField(controlName, bindFlags);
if (fi == null)
{
are.Set();
return null;
}
else
{
object theControl = fi.GetValue(theForm);
Type tControl = theControl.GetType();
PropertyInfo pi = tControl.GetProperty(controlPropertyName);
object result = null;
if (pi == null)
{
are.Set();
return null;
}
else
{
result = pi.GetValue(theControl, null);
are.Set();
return result;
}
}
}
}
/// <summary>
/// Set Control Property
/// </summary>
/// <param name="theForm">the form which your control belongs to</param>
/// <param name="controlName">the control name you want to set value</param>
/// <param name="controlPropertyName">the property name of the control</param>
/// <param name="newValue">the new value you want to set for the property of the control</param>
delegate void setControlPropertyHandler(Form theForm, string controlName, string controlPropertyName, object newValue);
public void SetControlPropertyByPropertyName(Form theForm, string controlName, string controlPropertyName, object newValue)
{
if (theForm == null)
return;
if (theForm.InvokeRequired)
{
setControlPropertyHandler setHandler = new setControlPropertyHandler(SetControlPropertyByPropertyName);
object oparams = new object[] {theForm ,controlName , controlPropertyName , newValue };
theForm.Invoke(setHandler, oparams);
are.WaitOne();
}
else
{
Type tForm = theForm.GetType();
FieldInfo fi = tForm.GetField(controlName,bindFlags );
if (fi == null)
{
are.Set();
return;
}
else
{
object theControl = fi.GetValue(theForm);
Type tControl = theControl.GetType();
PropertyInfo pi = tControl.GetProperty(controlPropertyName);
if (pi == null)
{
are.Set();
return;
}
else
{
try
{
pi.SetValue(theControl, newValue, null);
}
catch
{
//it's a invalid value for the property
return;
}
finally
{
are.Set();
}
}
}
}
}
/// <summary>
/// Invoke a Method, such as "button_click" event
/// </summary>
/// <param name="theForm">the form which the method belongs to</param>
/// <param name="methodName">the method name you want to invoke</param>
/// <param name="parameters">the parameters the method needed</param>
delegate void invokeMethodHandler(Form theForm, string methodName, params object[] parameters);
public void InvokeMethod(Form theForm, string methodName, params object[] parameters)
{
if (theForm == null)
return;
if (theForm.InvokeRequired)
{
invokeMethodHandler invokeHandler = new invokeMethodHandler(InvokeMethod);
object oparams = new object[] {theForm, methodName, parameters};
theForm.Invoke(invokeHandler, oparams);
are.WaitOne();
}
else
{
Type tForm = theForm.GetType();
MethodInfo mi = tForm.GetMethod(methodName, bindFlags);
if (mi == null)
{
are.Set();
return;
}
else
{
try
{
mi.Invoke(theForm, parameters);
}
catch
{
return;
}
finally
{
are.Set();
}
}
}
}
#endregion
/// <summary>
/// To launch the Application under test(AUT)
/// return the Form
/// </summary>
/// <param name="appPath">the path of exe file</param>
/// <param name="formName">the form name of which you want to get</param>
/// <returns>the form you want to get</returns>
public Form LaunchApp(string appPath, string formName)
{
Form theForm = null;
if (!System.IO.File.Exists(appPath))
return null;
string theFormName = formName;
Assembly ass = Assembly.LoadFrom(appPath);
Type tForm = ass.GetType(formName);
if (tForm == null)
return null;
theForm = (Form)ass.CreateInstance(tForm.FullName);
if (theForm == null)
return null;
AppState aState = new AppState(theForm);
ThreadStart ts = new ThreadStart(aState.Run);
Thread theThread = new Thread(ts);
theThread.IsBackground = true;
theThread.SetApartmentState (ApartmentState.STA);
theThread.Start();
return theForm;
}
}
//this is a wrapper class for ThreadStart method call
class AppState
{
Form theForm;
public AppState(Form form)
{
theForm = form;
}
public void Run()
{
Application.Run(theForm);
}
}
}
using System.Threading;
using System.Reflection;
using System.Windows.Forms;
using System.Text;
namespace WinFC
{
/// <summary>
/// Qijie Xue
/// Writed at 8/13/2011
/// </summary>
public class FormClass
{
static AutoResetEvent are = new AutoResetEvent(false);
const BindingFlags bindFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
#region get, set, invoke methods
/// <summary>
/// Get Form property
/// </summary>
/// <param name="theForm">the form you want to get property</param>
/// <param name="propertyName">the property name of the form</param>
/// <returns>the value for the property of the form</returns>
delegate object getFormPropertyHandler(Form theForm, string propertyName);
public object GetFormPropertyByPropertyName(Form theForm, string propertyName)
{
if (theForm == null)
return null;
if (theForm.InvokeRequired)
{
getFormPropertyHandler phandler = new getFormPropertyHandler(GetFormPropertyByPropertyName);
object result = null;
object[] oparams = new object[] {theForm , propertyName};
result = theForm.Invoke(phandler, oparams );
are.WaitOne();
return result;
}
else
{
object result = null;
Type t = theForm.GetType();
PropertyInfo pi = t.GetProperty(propertyName);
if (pi == null)
{
are.Set();
return null;
}
else
{
result = pi.GetValue(theForm, null);
are.Set();
return result;
}
}
}
/// <summary>
/// Set Form Property
/// </summary>
/// <param name="theForm">the form you want to set property</param>
/// <param name="propertyName">the propery name of form</param>
/// <param name="newValue">the new value of this propery you want to set</param>
delegate void setFormPropertyHandler(Form theForm, string propertyName, object newValue);
public void SetFormPropertyByPropertyName(Form theForm, string propertyName, object newValue)
{
if (theForm == null)
return;
if (theForm.InvokeRequired)
{
setFormPropertyHandler setHandler = new setFormPropertyHandler(SetFormPropertyByPropertyName);
object oparams = new object[] { theForm, propertyName, newValue };
theForm.Invoke(setHandler, oparams);
are.WaitOne();
}
else
{
Type t = theForm.GetType();
PropertyInfo pi = t.GetProperty(propertyName);
if (pi == null)
{
are.Set();
return;
}
else
{
try
{
pi.SetValue(theForm, newValue, null);
}
catch
{
//it's a invalid value for this property
return;
}
finally
{
are.Set();
}
}
}
}
/// <summary>
/// Get Control property
/// </summary>
/// <param name="theForm">the form which the control belongs to</param>
/// <param name="controlName">the control name which you want to get</param>
/// <param name="controlPropertyName">the property name of the control you want to get</param>
/// <returns>the value for the property of the control</returns>
delegate object getControlPropertyHandler(Form theForm, string controlName, string controlPropertyName);
public object GetControlPropertyByPropertyName(Form theForm, string controlName, string controlPropertyName)
{
if (theForm == null)
return null;
if (theForm.InvokeRequired)
{
getControlPropertyHandler getHandler = new getControlPropertyHandler(GetControlPropertyByPropertyName);
object result = null;
object oparams = new object[] {theForm , controlName , controlPropertyName };
result = theForm.Invoke(getHandler, oparams);
are.WaitOne();
return result;
}
else
{
Type tForm = theForm.GetType();
FieldInfo fi = tForm.GetField(controlName, bindFlags);
if (fi == null)
{
are.Set();
return null;
}
else
{
object theControl = fi.GetValue(theForm);
Type tControl = theControl.GetType();
PropertyInfo pi = tControl.GetProperty(controlPropertyName);
object result = null;
if (pi == null)
{
are.Set();
return null;
}
else
{
result = pi.GetValue(theControl, null);
are.Set();
return result;
}
}
}
}
/// <summary>
/// Set Control Property
/// </summary>
/// <param name="theForm">the form which your control belongs to</param>
/// <param name="controlName">the control name you want to set value</param>
/// <param name="controlPropertyName">the property name of the control</param>
/// <param name="newValue">the new value you want to set for the property of the control</param>
delegate void setControlPropertyHandler(Form theForm, string controlName, string controlPropertyName, object newValue);
public void SetControlPropertyByPropertyName(Form theForm, string controlName, string controlPropertyName, object newValue)
{
if (theForm == null)
return;
if (theForm.InvokeRequired)
{
setControlPropertyHandler setHandler = new setControlPropertyHandler(SetControlPropertyByPropertyName);
object oparams = new object[] {theForm ,controlName , controlPropertyName , newValue };
theForm.Invoke(setHandler, oparams);
are.WaitOne();
}
else
{
Type tForm = theForm.GetType();
FieldInfo fi = tForm.GetField(controlName,bindFlags );
if (fi == null)
{
are.Set();
return;
}
else
{
object theControl = fi.GetValue(theForm);
Type tControl = theControl.GetType();
PropertyInfo pi = tControl.GetProperty(controlPropertyName);
if (pi == null)
{
are.Set();
return;
}
else
{
try
{
pi.SetValue(theControl, newValue, null);
}
catch
{
//it's a invalid value for the property
return;
}
finally
{
are.Set();
}
}
}
}
}
/// <summary>
/// Invoke a Method, such as "button_click" event
/// </summary>
/// <param name="theForm">the form which the method belongs to</param>
/// <param name="methodName">the method name you want to invoke</param>
/// <param name="parameters">the parameters the method needed</param>
delegate void invokeMethodHandler(Form theForm, string methodName, params object[] parameters);
public void InvokeMethod(Form theForm, string methodName, params object[] parameters)
{
if (theForm == null)
return;
if (theForm.InvokeRequired)
{
invokeMethodHandler invokeHandler = new invokeMethodHandler(InvokeMethod);
object oparams = new object[] {theForm, methodName, parameters};
theForm.Invoke(invokeHandler, oparams);
are.WaitOne();
}
else
{
Type tForm = theForm.GetType();
MethodInfo mi = tForm.GetMethod(methodName, bindFlags);
if (mi == null)
{
are.Set();
return;
}
else
{
try
{
mi.Invoke(theForm, parameters);
}
catch
{
return;
}
finally
{
are.Set();
}
}
}
}
#endregion
/// <summary>
/// To launch the Application under test(AUT)
/// return the Form
/// </summary>
/// <param name="appPath">the path of exe file</param>
/// <param name="formName">the form name of which you want to get</param>
/// <returns>the form you want to get</returns>
public Form LaunchApp(string appPath, string formName)
{
Form theForm = null;
if (!System.IO.File.Exists(appPath))
return null;
string theFormName = formName;
Assembly ass = Assembly.LoadFrom(appPath);
Type tForm = ass.GetType(formName);
if (tForm == null)
return null;
theForm = (Form)ass.CreateInstance(tForm.FullName);
if (theForm == null)
return null;
AppState aState = new AppState(theForm);
ThreadStart ts = new ThreadStart(aState.Run);
Thread theThread = new Thread(ts);
theThread.IsBackground = true;
theThread.SetApartmentState (ApartmentState.STA);
theThread.Start();
return theForm;
}
}
//this is a wrapper class for ThreadStart method call
class AppState
{
Form theForm;
public AppState(Form form)
{
theForm = form;
}
public void Run()
{
Application.Run(theForm);
}
}
}