NUnitForms is a pretty awsome tool for GUI unit testing.
However it lacks one major thing. You can't test a whole exe or dll.
For example if you have a MyTestApp.exe with various win forms etc., you can't just run it and test it's gui.
And i really wanted to do it because our app sets a lot of other stuff and it's pretty complex so you can't just
call Form.Show() and start playing with it.
So with a lot experimenting and reading and going through NUnitForms source code I've come up with a way to do it.
The first thing to know is how NUnitForms work. There are a lot of examples like this one which was the first to read on my list.
Every one of these examples creates an instance of the form you want to test, calls it's Show() method and then performs tests.
This is because NunitForms have their own application message loop that feeds messages to displayed forms.
So what you have to do is disable your Apps message loop. You can do that by returning the Main() function
(The main Entry point for your application) before it calls it's Application.Run().
This is the original Main function:
[STAThread]
static int Main(string[] argsFromMain)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AppRun();
Application.Run();
return 0;
}
static void AppRun()
{
Form1 f = new Form1();
f.Show();
}
Now we want to disable our apps message loop so we add a startup argument "/nomessageloop":
[STAThread]
static int Main(string[] argsFromMain)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AppRun();
if (argsFromMain[0] == "nomessageloop")
return 0;
Application.Run();
return 0;
}
static void AppRun()
{
Form1 f = new Form1();
f.Show();
}
Now if you try to run your app with "/nomessageloop" parameter your app will show the starting form for a moment and then exit.
This is exactly what we want.
I'm assuming you're familiar with NUnit testing.
Now lets see how we can use this in a test. This is a simple test class called Tests.cs:
using System;
using System.Text;
using NUnit.Extensions.Forms;
using NUnit.Framework;
using System.Reflection;
namespace NUnitFormsTests
{
[TestFixture]
public class Tests : NUnitFormTest
{
string exeFileName;
public override void Setup()
{
exeFileName = @"D:\MyTestApp.exe";
string[] argsFromMain = new string[1];
argsFromMain[0] = "/nomessageloop";
AppDomain.CurrentDomain.ExecuteAssembly(exeFileName, AppDomain.CurrentDomain.Evidence, argsFromMain);
}
[Test]
public void Test1()
{
// This assumes that MyTestApp.exe has a textBox named textBox1 and
// 2 buttons named button1 and button2
// button1.Click sets the textBox1.Text to "This is a test button1"
// button2.Click sets the textBox1.Text to "This is a test button2"
// So we're testing if that's true.
// this test should pass.
TextBoxTester textbox1 = new TextBoxTester("textBox1");
ButtonTester btn1 = new ButtonTester("button1");
ButtonTester btn2 = new ButtonTester("button2");
string expected1 = "This is a test button1";
string expected2 = "This is a test button2";
btn1.Click();
Assert.AreEqual(expected1, textbox1.Text, "Correct button1 click");
btn2.Click();
Assert.AreEqual(expected2, textbox1.Text, "Correct button2 click");
}
}
}
Also since now our app is running in the context of the unit test, you have to put anything you have in your apps app.config
into the app.config of the project that holds Tests.cs. It will be read from there.
The only problem i've run into so far is Drag and Drop registration, but this isn't a critical error.
If I encounter any more i'll post them.
UPDATE: I've found a solutions to the Drag and Drop problem and i've posted it here