The simplest way is an anonymous method passed into Label.Invoke
:
// Running on the worker thread
string newText = "abc";
form.Label.Invoke((MethodInvoker)delegate {
// Running on the UI thread
form.Label.Text = newText;
});
// Back on the worker thread
Notice that Invoke
blocks execution until it completes--this is synchronous code. The question doesn't ask about asynchronous code, but there is lots of content on Stack Overflow about writing asynchronous code when you want to learn about it.
OK, your app sounds large! I can share my experiences around an application we engineered recently; it was a GUI talking web services to a server that in turn contacted multiple databases and other web services. The client base was around 15,000 users… Either way - this is a lot of work no matter how you approach it; the upside is it will help you not chew your nails off each time you make a release!
MVVM
In general I would also recommend the MVVM pattern and do as much testing as possible without the GUI. GUI testing is just plain hard! I like Josh Smith’s article on MSDN: "WPF Apps With The Model-View-ViewModel Design Pattern" (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx)
Test Scripting
The trick with this app was that we had a lot to test, the guts of it were constantly moving and there were (strangely enough) not enough people to get the testing job done for each iteration.
My solution was to come up with a custom testing tool that leveraged existing libraries. We had a simple script engine that read a file and executed commands. In effect we developed a DSL (http://en.wikipedia.org/wiki/Domain-specific_language) for testing our specific application. The DSL included some simple commands to signal what "window" it was testing, any specific "setup" signals and then a series of commands followed by assertions. It looked something like this:
Test NewXyzItem
Setup Clear_items
Press Some_button
Enter_text_into Name Bobby Joe
(...)
Press Save
Assert_db_has_itemX SomeKey
The format of each line is
"command" "argument" [data]
The scripts go into groups of directories and the "test runner" loads them up, parses them and executes them. Creating logs and reports as you go is useful, I got added in hook for making screen-shots etc which came in handy. If you are interested in implementing something likke this and would like a hand let me know.
The handy thing here was that we could make blanket changes to the test strategy.
Writing the scripts becomes pretty simple which is important because you end up with many, many scripts. The controls are discovered by name so you follow a convention (e.g. “Name” may be "NameTextBox" in code, or “Save” could be "SaveButton").
You can actually harness NUnit etc to be your test runner too.
NOTE - Just run the tests interactively, getting GUI test to work with CI is difficult and problematic...
Data and Testing
One major thing here is that the data management was a huge part of the test problem and cannot be overlooked. Our “fresh deployment” was also very long but some parts were external and we had no control over the freshness of the data. The way we handled the cleaning was to provide hooks through the scripting that allowed us to easily remove objects before tests. Not optimal but was rarely an issue.
Libraries
The library that you may find most useful in "White" (http://white.codeplex.com/) It can test windows apps in general – i.e both WPF and WinForms. Essentially you end up coding things like this:
Button button = window.Get<Button>("SaveButton");
button.Click();
If your app makes async calls you will need to come up with a strategy for the test runner to know when the async call is finished, perhaps though the status bar or something. It depend how you hook in…
Again, a lot of work but it’s worth it.
PK :-)
Best Answer
Basic guiding principle: if they want you to test something, testers need a way to get the application into that state, and once in that state, a way to validate that the state is correct.
So the first thing is to ensure they understand that automation is programming and the UI is your API.
Agreement to not arbitrarily change the UI -- if tester Bob see that the component changed from a button to a link, and it matches the spec, clicks and goes on. While a relatively easy code change in automation, it is a change that may have to be made in multiple locations. (your job as a tester is to understand that change happens and minimize the cost of maintenance; their job is to only make important changes and to understand the impact)
A way to determine which page you are on.... Bob can tell the difference between login and order entry, but how will automation know? If an enter field with the 'Username' label, the login page. If an entry field with Order number, the order field.
Not good -- better practice is a consistent UI element to identify the page -- page title, hidden component, etc.
A way to uniquely identify every element that you need to interact with (click, type in, verify, etc.) And not INPUT_42....
Ask the developers what information that testers can provide them to speed their debugging, and ask them to put it into a log file
Ability to dump state of the program
Consistent error handling & reporting (also just good UI design)