I want some Moore

Blog about stuff and things and stuff. Mostly about SQL server and .Net
posts - 176, comments - 1797, trackbacks - 33

My Links

SQLTeam.com Links

News

Hi! My name is 
Mladen Prajdić  I'm from Slovenia and I'm currently working as a .Net (C#) and SQL Server developer. I'm a MCP and MCTS for SQL Server. I also speak at local user group meetings and conferences like NT Conference 
Welcome to my blog.

Search this Blog

My Blog Feed via Email


Users Online: who's online

Article Categories

Archives

Post Categories

Cool software

Other Blogs

Other stuff

SQL stuff

Compiled application exe GUI testing with NUnitForms

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

 

 

kick it on DotNetKicks.com

Print | posted on Thursday, March 01, 2007 11:06 AM

Feedback

# re: Compiled application exe GUI testing with NUnitForms

Ah, the joys of forms unit testing. What I miss for the most part is that NUnitForms doesn't deal with non-standard modal dialogs (IOW non-MessageBox stuff). Or at least it didn't...
3/1/2007 1:20 PM | Miha Markic

# re: Compiled application exe GUI testing with NUnitForms

as far as i know it does.

you have the ModalFormTester and it's ExpectModal function that takes a delegate in which you put your test.

works preety ok for me.
3/1/2007 1:32 PM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

you're right.
it's fixed.
thanx
3/8/2007 4:52 PM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

Many thanks for your article.

1)
I have modified this line
if (argsFromMain[0] == "nomessageloop")
to
if (argsFromMain[0] == "/nomessageloop")
so that the strings match.


2)
I have modified your code because if I run the .exe (not the test) and I close the program the main window disappears but the process does not end:

[STAThread]
static void Main(string[] argsFromMain)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 f = new Form1();
f.Show();
if (argsFromMain != null && argsFromMain.Length > 0 && argsFromMain[0] == "/nomessageloop")
return;
Application.Run(f);
}

Cheers.
Marco.
4/27/2007 4:49 PM | marco

# re: Compiled application exe GUI testing with NUnitForms

Note:
string[] argsFromMain = new string[1];
argsFromMain[1] = "/nomessageloop";

should be

string[] argsFromMain = new string[1];
argsFromMain[0] = "/nomessageloop";
7/2/2007 11:59 AM | Andrew

# re: Compiled application exe GUI testing with NUnitForms

fixed.
thanx for reminding me... was meaning to fix it before but i forgot :)
7/2/2007 12:02 PM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

If you can't test at least the vast majority of your UI with NUnitForms, there's possibly something wrong with the way you're doing TDD. Are you using NMock?
9/4/2007 6:32 AM | Duncan Bayne

# re: Compiled application exe GUI testing with NUnitForms

problem was that we didn't do TDD on this project. we put auto-tests at the end of the cycle...
so this was the only way to implement it as far as could figure it out.
but then i'm no master of TDD :)
9/4/2007 9:51 AM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

I haven't seen any examples on how to test a winforms datagrid. There are methods for this built into NUnitASP.

For instance, I would like to test the values returned into a datagrid as well as fire the event "DoubleClick" on a specific row in the datagrid.

Does anyone have any experience with this?

In the meantime, I am getting around the problem by using the mouse methods to double click the datagrid, but I can only test the results of that action, not the data within the datagrid.

Any help is appreciated.
10/22/2007 11:30 PM | BGaither

# re: Compiled application exe GUI testing with NUnitForms

there is no built in datagrid support.
you'll have to build your own custom tester for this.
you can fire event with the method FireEvent
you can test the data in the grid by accessing it's DataSource Property.
10/23/2007 10:10 AM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

I have a problem when some other objects initialized. I got an error box when ExecuteAssembly:
Se produjo una excepción en el inicializador de tipo de 'Spring.Context.Support.ContextRegistry'.

Should I have to add all the .dlls of my tested-application as referneces, and initialized it?
It isnt enough to set the results directory, and folder references as the same of my tested-app.

By the way, I haven't access to the source of the tested-app.
Any sugestions??
thanx!!

10/24/2007 8:26 PM | lt

# re: Compiled application exe GUI testing with NUnitForms

yes you should add references to all asseblies to your nunit project.
10/24/2007 8:38 PM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

I am using a 3rd party control, "SPREAD" in vb.net project.
I m using NUnitForms for testing the forms.
But i m unable to test the Spread Functionality as NUnit is unable to detect the 3rd party control.
Can Anybody suggest me how to test a 3rd party control by NUnitForms?
12/17/2007 11:22 AM | Sonal Dewle

# re: Compiled application exe GUI testing with NUnitForms

nunit can detect 3rd party controls just fine.
just use UserControlTester.
or create a new tester derived from usercontrl tester
12/17/2007 11:42 AM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

I m unable to get a UserControlTester class in NUnitForms 2.0 Aplha 5 version.
Ca u plz give me the NUnitForms version where i can access UserControlTester class?
12/18/2007 12:40 PM | Sonal Dewle

# re: Compiled application exe GUI testing with NUnitForms

sorry, i meant ControlTester. derive your own tester from ControlTester
12/18/2007 1:06 PM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

Hello,

How can i run my Application, that i want to test, without blocking the NUnitforms tests?

I must run my Application lick here:

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyApplicationContext(new string[] {})); //this blocks everything

Thanks
7/16/2008 2:34 PM | Willi

# re: Compiled application exe GUI testing with NUnitForms

not quite sure what you mean by blocking Willi.
7/16/2008 3:12 PM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

How can i back from Application.Run to place where was is called?

i must use Application.Run( new MyMainForm() ) to run my application?
so i can´t use this way:

MyMainForm myForm = new MyMainForm();
myForm.ShowDialog();

Thanks
7/16/2008 3:19 PM | Willi

# re: Compiled application exe GUI testing with NUnitForms

I did it like this, but i couldn't debug it:
.....
ApplicationTestStart _applicationTestStart = new ApplicationTestStart();
ThreadStart ts = new ThreadStart(_applicationTestStart.Run);
Thread t1 = new Thread(ts);
t1.Start();
--------------------------------------------------------------------------------
public class ApplicationTestStart
{
public ApplicationTestStart()
{
}

public void Run()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyApplicationContext(new string[] {}));
}
}
7/16/2008 3:37 PM | Willi

# re: Compiled application exe GUI testing with NUnitForms

so why exactly must u use Application.Run( new MyMainForm() ) ?
7/16/2008 3:52 PM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

To run my Application, that i want to test with NUnitforms.
So with:
Application.Run(new MyApplicationContext(new string[] {}));

I can not run it with:
Form1 f = new Form1();
f.Show();... or something like this...
7/16/2008 4:00 PM | Willi

# re: Compiled application exe GUI testing with NUnitForms

well we do this and it works just fine:
protected override void Start( ApplicationContext application )
{
// for NUnitForms Testing
if( parameterService.Start.ContainsKey( "nomessageloop" ) )
return;

// The magic message loop
System.Windows.Forms.Application.Run( application );
}
7/16/2008 4:13 PM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

and my application use Backgroundworker!
7/16/2008 4:14 PM | Willi

# re: Compiled application exe GUI testing with NUnitForms

so? ours is also completly async in nature.
7/16/2008 4:15 PM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

what do you mean with: parameterService.Start.ContainsKey( "nomessageloop" )....
where can I find it?
7/16/2008 5:21 PM | Willi

# re: Compiled application exe GUI testing with NUnitForms

parameterService.Start is a string[] that contains input parameters to the Main(string[] args) method. it's just args.
7/16/2008 5:26 PM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

but
System.Windows.Forms.Application.Run( application )
bolcks also the course of the application.

Just for example:

public class ProgramTEST
{
public ProgramTEST()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyApplicationContext(new string[] {})); // -->>>This bolcks the course of the application.
}

public ControlTester buttonTester;

public void Test()
{
buttonTester = new ControlTester("_okButton", "myForm");

buttonTester.FireEvent("Click");

}
}
}
7/17/2008 9:28 AM | Willi

# re: Compiled application exe GUI testing with NUnitForms

maybe you haven't read this blog post carefully...
if you pass nomessageloop as a startup parameter the Application.Run is not called.
7/17/2008 10:22 AM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

I have do it like this, but it bolcks by:

AppDomain.CurrentDomain.ExecuteAssembly(exeFileName, AppDomain.CurrentDomain.Evidence, argsFromMain);

thanks
7/17/2008 11:05 AM | willi

# re: Compiled application exe GUI testing with NUnitForms

uff...
if you do AppDomain.CurrentDomain.ExecuteAssembly(exeFileName, AppDomain.CurrentDomain.Evidence, argsFromMain);

the i have no clue on how you might be able to test this.
7/17/2008 11:34 AM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

Hi,
My application has following Main() code

[STAThread]
static void Main()
{
Application.Run(new CSI_Main());
}

How we can use "nomessageloop" for this context.
2/4/2009 4:39 AM | rajuMSN

# re: Compiled application exe GUI testing with NUnitForms

[STAThread]
static void Main()
{
Form f = new CSI_Main();
if (not nomessageloop in params when your app starts)
{
Application.Run(f);
}
}
2/4/2009 11:26 AM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

Hi Team!

My name's Ngoc.
Would you mind if I asked you some questions about NUnitForms.

1.Following your example. The form I want to test is displayed; but after that I can't find any controls and corresponding properties. NoSuchControlException occur.

2. Instead of create an instance of the form I want to test or override method Setup to create an instance, I attach to the form. But after that I can't also find any controls and corresponding properties. NoSuchControlException occur.But I really want to do it.

Would you please let me know what should I do asap?
All of the imformation that you providing and your helping is really useful and important to me.

Thanks for your time and consideration.
Best regards.
Pham Ngoc.
4/17/2009 4:06 AM | Pham Ngoc

# re: Compiled application exe GUI testing with NUnitForms

hi,
without seeing some acctual code i can't really help you.
4/17/2009 12:29 PM | Mladen

# re: Compiled application exe GUI testing with NUnitForms

Hello together,

i am trying to test a VB Windows Forms Application with NUnitForms

i although have to start the whole application and not only one Form.

now i have no main method, where i could disable the message loop

i only set the start Form at the project properties...

does anybody knows what i could do?

thanks
4/22/2009 11:04 AM | Romka

# re: Compiled application exe GUI testing with NUnitForms

hi,
without seeing some acctual code i can't really help you.
4/22/2009 11:36 AM | Mladen

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 4 and 6 and type the answer here:

Powered by: