After having done heck of research on how do I go about automating my Windows8 app, from among lot many third party tools to Windows UIA itself, I realized UIA was the way to go.
But then there are hardly any samples, that would help you get started with this. There are a couple available for Windows7, but Metro as we all know is a new world of its own.
This post would help you get started with Windows UI Automation for a Windows 8 (aka Metro) app, in C#, in just a few steps. All this information is actually gathered from a variety of tutorials, blogs, msdn links, forums, scattered all over the web and put together in this post.
You can create a Unit Test Project from
Templates>Other Languages>Visual C# > Test > Unit Test Project
and your test cases would need all the below workflow, after which you can 'assert' all that you want to.
(I'm working on Visual Studio 2012, Ultimate )
1. Auto-launching of your app
This post I must say has been an amazing source of information. It also mentions how do you go about launching your app in C++.
The process and all the content stays true, but there is this below piece of code in C#, doing the same. "<appID>" here is the app ID of the application you want to launch.
public static void launchApp()
{
ApplicationActivationManager appActiveManager =
new ApplicationActivationManager();
uint pid;
appActiveManager.ActivateApplication("<appID>",
null, ActivateOptions.None, out pid);
}
public enum ActivateOptions
{
None = 0x00000000,
DesignMode = 0x00000001,
NoErrorUI = 0x00000002,
NoSplashScreen = 0x00000004,
}
[ComImport,Guid("2e941141-7f97-4756-ba1d-9decde894a3d"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IApplicationActivationManager
{
IntPtr ActivateApplication([In] String appUserModelId,
[In] String arguments,
[In] ActivateOptions options,
[Out] out UInt32 processId);
IntPtr ActivateForFile([In] String appUserModelId,
[In] IntPtr /*IShellItemArray* */ itemArray,
[In] String verb,
[Out] out UInt32 processId);
IntPtr ActivateForProtocol([In] String appUserModelId,
[In] IntPtr /* IShellItemArray* */itemArray,
[Out] out UInt32 processId);
}
[ComImport, Guid("45BA127D-10A8-46EA-8AB7-56EA9078943C")]
//Application Activation Manager
class ApplicationActivationManager:IApplicationActivationManager
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)/*, PreserveSig*/]
public extern IntPtr ActivateApplication(
[In] String appUserModelId,
[In] String arguments,
[In] ActivateOptions options,
[Out] out UInt32 processId);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
public extern IntPtr ActivateForFile(
[In] String appUserModelId,
[In] IntPtr /*IShellItemArray* */itemArray,
[In] String verb,
[Out] out UInt32 processId);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
public extern IntPtr ActivateForProtocol(
[In] String appUserModelId,
[In] IntPtr /* IShellItemArray* */itemArray,
[Out] out UInt32 processId);
}
2. Accessing the controls :
You can inspect about the controls present in your app, using "Inspect.exe", available with Windows Kits. For me it is present at :
"C:\Program Files\x86)\Windows Kits\8.0\bin\x64".
Now for the below code to get working. Make sure to include these dll's beside the default ones :
> PresentationCore.dll
> PresentationFramework.dll
> UIAComWrapper.dll [Most important]
> WpfUtilities.dll
I'm attaching them all here, for easy access or you can go ahead and search them in your Visual Studio installed location.
Below piece of code is just a sample to get you started to access any type of controls in your app. Here I'm just trying to find a button and click it.
(Note: All Windows UIA code would work just fine as seen in the msdn docs.)
//Gives you the root element i.e 'Desktop'
AutomationElement aeDesktop = AutomationElement.RootElement;
//Make a condition to find your app by 'NameProperty'
Condition appCondition =
new PropertyCondition(AutomationElement.NameProperty,
"MyApp", PropertyConditionFlags.IgnoreCase);
AutomationElement aeAppWindow =
aeDesktop.FindFirst(TreeScope.Children,
appCondition);
AutomationElement aePane =
aeAppWindow.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.ControlTypeProperty,
ControlType.Pane));
AutomationElementCollection aeButtons =
aePane.FindAll(TreeScope.Descendants,
new PropertyCondition(AutomationElement.ControlTypeProperty,
ControlType.Button));
//Click on sample button
System.Drawing.Point p = aeButtons[3].GetClickablePoint();
Mouse.MoveTo(p);
Mouse.Click(MouseButton.Left);
Thread.Sleep(2000);
3. Closing your app
Hitting an 'Alt + F4' closes your app. You can do the same by this below line of code :
SendKeys.SendWait("%{F4}");
["SendKeys" is available in Systems.Windows.Forms dll]
That is all. You have now successfully automated a simple workflow of your Metro app. Good luck automating your next Windows app !
Post in your comments if you have any doubts or you find a better way of doing the same thing or better still, you find the post useful ! :)