I always work close to the UI. Actually, most of the time elbow deep in the GUI. But I also love testing. One thing you don't want to do, is drive you GUI for unit testing purpose (there are other uses for that but not unit testing...trust me on that). So it would be great to fire events at will, or in the test code but that's not an option either. To much trouble.
Another way is to just open up the event handlers to the public and execute the code and that, in a testing sense feels a lot better. But again, event handlers is not a good thing to open up to the public, especially when you are building libraries.
I remember Marcus Widerbeg and I had a few discussions around this, how to maintain testability but retain protection. I think the following can develop further but It will do for most scenarios.
There are an attribute that actually seems to be made for this scenario. InternalsVisibleTo... This will present internal methods and fields to a specific strong named and signed assembly, that should be the unit test assembly. It's quite simple. Just change the protection from private to internal. Sign your test assembly and set the attribute in the AssemblyInfo.cs, together with the public key for your test assembly, like this:
[assembly: InternalsVisibleTo("Haqwin.Gui.UnitTests, PublicKey=00...cb")]
To find the public key, just build your solution and run the sn.exe tool like this:
sn -Tp Haqwin.Gui.UnitTests.dll
So now I can use this to unit test most of my UI code as well as automate the Function and Integration tests. Driving them almost as close as executing the actual interface. Here is an example of testing the EventHandler for a button:
[Test]
internal void NavigateMetaDataEditor()
{
Assert.AreEqual(DockStyle.Fill, _InitializeMetaData.Dock);
Assert.AreEqual(DockStyle.None, _EditMetaDataControl.Dock);
_InitializeMetaData.NextControl = _EditMetaDataControl;
_InitializeMetaData.NextControlButton_Click(this, new EventArgs());
Assert.AreEqual(DockStyle.None, _InitializeMetaData.Dock);
Assert.AreEqual(DockStyle.Fill, _EditMetaDataControl.Dock);
}
The other solution to this problem, is to use reflection to get to the private methods but I'll save that for another post