Here is what I ended up doing:
First, the Extensions class:
public static class Extensions
{
#region Public Methods and Operators
public static Stopwatch ClickButton(this Form form, string controlName)
{
var controls = form.Controls.Find(controlName, true);
if (controls.Any())
{
var control = controls[0] as Button;
if (control != null)
{
MethodInfo mi = typeof(Button).GetMethod("OnClick", BindingFlags.NonPublic | BindingFlags.Instance);
var stopWatch = Stopwatch.StartNew();
mi.Invoke(
control,
new object[]
{
EventArgs.Empty
});
return stopWatch;
}
}
throw new ApplicationException("Control not found or of invalid Type");
}
public static Delegate ConvertDelegate(Delegate originalDelegate, Type targetDelegateType)
{
return Delegate.CreateDelegate(targetDelegateType, originalDelegate.Target, originalDelegate.Method);
}
public static object GetControlProperty<T>(this Form form, string controlName, string propertyName) where T : class
{
var controls = form.Controls.Find(controlName, true);
if (controls.Any())
{
var control = controls[0];
PropertyInfo pi = typeof(T).GetProperty(propertyName);
return pi.GetValue(control, null);
}
throw new ApplicationException("Control not found or of invalid Type");
}
public static void ObserveControlEvents<T>(this Form form, string controlName, string eventName, Action<object, object> action) where T : class
{
var controls = form.Controls.Find(controlName, true);
if (controls.Any())
{
var control = controls[0] as T;
if (control != null)
{
EventInfo ei = typeof(T).GetEvent(eventName);
if (ei != null)
{
Delegate handler = ConvertDelegate(action, ei.EventHandlerType);
ei.AddEventHandler(control, handler);
}
}
}
}
public static void ObserveGrid(this Form form, string controlName, string eventName, Action<object, object> action)
{
var controls = form.Controls.Find(controlName, true);
if (controls.Any())
{
var control = controls[0] as DataGridView;
if (control != null)
{
EventInfo ei = typeof(DataGridView).GetEvent(eventName);
if (ei != null)
{
Delegate handler = ConvertDelegate(action, ei.EventHandlerType);
ei.AddEventHandler(control, handler);
}
}
}
}
public static void SetControlProperty<T>(this Form form, string controlName, string propertyName, object value) where T : class
{
var controls = form.Controls.Find(controlName, true);
if (controls.Any())
{
var control = controls[0];
PropertyInfo pi = typeof(T).GetProperty(propertyName);
pi.SetValue(control, value, null);
}
}
public static void SetFormProperty(this Form form, string controlName, object value)
{
var controls = form.Controls.Find(controlName, true);
if (controls.Any())
{
var control = controls[0];
PropertyInfo pi = typeof(Control).GetProperty("Text");
pi.SetValue(control, value, null);
}
}
#endregion
}
Now, in my unit tests I can create the form, set values, trigger and observe the events:
[TestFixture]
public class FormsTests
{
#region Public Methods and Operators
[TestCase(null, null, null, 1000)]
[TestCase("Kim", null, null, 500)]
[TestCase("Kim", null, "Akers", 250)]
[TestCase("Kim", "B", "Abercrombie", 100)]
public void InsuredSearcherResponseTimeWithReflectionTest(string firstName, string middleName, string lastName, long milliseconds)
{
var monitor = new SemaphoreSlim(1);
monitor.Wait();
var form = new Insured();
form.SetControlProperty<TextBox>("tbFirstName", "Text", firstName);
form.SetControlProperty<TextBox>("tbMiddleName", "Text", middleName);
form.SetControlProperty<TextBox>("tbLastName", "Text", lastName);
form.ObserveControlEvents<DataGridView>(
"dataGridView1",
"DataSourceChanged",
(sender, args) =>
{
Trace.WriteLine("Occured in delegate");
monitor.Release();
});
Trace.WriteLine("Executing");
var sw = form.ClickButton("btnSearch");
monitor.Wait();
sw.Stop();
Trace.WriteLine(String.Format("Row count was {0} took {1}ms to process", form.GetControlProperty<DataGridView>("dataGridView1", "RowCount"), sw.ElapsedMilliseconds));
Assert.IsTrue(sw.ElapsedMilliseconds < milliseconds);
}
[TestFixtureSetUp]
public void TestFixtureSetup()
{
var monitor = new SemaphoreSlim(1);
monitor.Wait();
var form = new Insured();
form.ObserveControlEvents<DataGridView>(
"dataGridView1",
"DataSourceChanged",
(sender, args) =>
{
Trace.WriteLine("Occured in delegate");
monitor.Release();
});
form.ClickButton("btnSearch");
monitor.Wait();
}
}
I hope this helps someone as well.