This fourth article in my series on Silverlight Testing with WebAii UI Automation FX assumes you have read all previous articles in the series. In this article we are going to start writing tests for our target application, with a focus on the basics of finding elements.
Conceptually writing automated UI tests is relatively simple and involves the following actions.
- Find a visual element
- Simulate user interaction with the element
- Assert the result of the interaction
Ok I accept this is a bit of an over simplification but in actual terms of what you do it is accurate. In the tests you write you will generally use WebAii for the first two and your testing framework (NUnit in our case) for the latter.
NB: WebAii does have it’s own Assert methods but as far as I can tell these are aimed at HTML elements so not really usable for Silverlight elements.
As the full name WebAii UI Automation Framework suggests WebAii is all about automating the user interface, but before you can automate an element you have to get access to it, so the vast majority of your tests will begin by finding an element, perhaps to validate it’s existence, but more often to simulate user interaction with it. So in this section we will explore the VisualFind object that provides you with the tools you will need.
An instance of the VisualFind object is available to you directly from a SilverlightApp or anything that derives from FrameworkElement (which is pretty much everything you will work with) in the guise of a Find property. VisualFind is context sensitive, any search it performs uses the owning object as the root for searching. This is important to understand because you could be forgiven for thinking the simplest thing to do is use the Find property of the Silverlight application, but doing so can end up traversing the whole visual tree to meet your request. In my opinion it is better to narrow your search wherever possible by starting it from an ancestor of the target element and the best way to do this is to create WebAii compatible wrappers for elements within your application, more about this later.
We’ll start building a test class to see how VisualFind works shortly, but first a word about naming convention. I am a big fan of concepts like BDD and TDD and defining requirements as a series of acceptance tests so I using a naming convention where the name of the class and test methods are actually specifications for the system, especially when it comes to UI automated tests. I also avoid using underscores in names, preferring to use the Pascal Case convention. However this is my personal preference and I have no intention of forcing this on anyone so feel free to name your classes and methods according to your own preference or team conventions. Obviously if you are using the samples I provide you are stuck with my convention, but again feel free to change this to suit your preferences. So to our tests.
Our first test is going to be a simple one that validates the following requirement specification:
Given a successful login
The users name is displayed
- Add a new class to the test project, I called mine GivenASuccesfulLogin.cs
- Edit the new class so that it is public and inherits from our TestBase class
- Decorate the class definition with the TestFixture attribute
- Add a public void method method for the test, I called mine TheUsersNameIsDisplayed
- Decorate the method with the Test attribute
-
You should end up with something like this:
1: using System;
2: using NUnit.Framework;
3:
4: namespace WebAii.Samples
5: {
6: [TestFixture]
7: public class GivenASuccessfulLogin: TestBase
8: {
9: [Test]
10: public void TheUsersNameIsDisplayed()
11: {
12: }
13: }
14: }
At this point you may remember from two articles back that running the test method would get us to the home page of the Primary Care Demonstrator of the MS CUI Silverlight reference application. Click on the link to open the target application and towards the top left corner in the green bar you should see the text Doctor: COX, Oliver (Dr) displayed. In our test method we want to verify that this text is displayed (note we don’t get to log in to this application so we have to imagine this has happened with with valid credentials for Dr Cox and we have landed here). So how do we figure out what to look for?
One option would be to simply find the expected text string and verify it’s existence like this:
1: Assert.IsNotNull(this.App.Find.ByText("COX, Oliver"));
Again you may remember in our base class from two articles back we get a reference to the first SilverlightApp found after loading the browser and captured it an App property so we have easy access in our tests. So here we are referencing the Find object of the Silverlight application and using it’s ByText method to search for the string.
In Silverlight plain text is always displayed in a System.Windows.Controls.TextBlock element so what FindText returns is a strongly typed ArtOfTest.WebAii.Silverlight.UI.TextBlock, which is a WebAii compatible wrapper for the standard control.
While this is nice and easy, is it efficient and would you really use this method. Even a cursory glance at the code for the Find.ByText method using Reflector shows that there are optimisations and strategies in use to speed up searching as much as possible (at some point I may just spend a some time on a deep dive into this stuff but for now I am relying on instinct and observation), but my instinct tells me this cannot be an efficient way to do things. Essentially Find.ByText must do two things, first find the TextBlock in the visual tree then match the Text property to our string. Also the fact that our find operation is rooted at the application level means the scope of the operation is potentially vast.
As mentioned previously I recommend you take some responsibility for narrowing the scope of find operations by first finding a parent element and using it’s Find property. However to do this you need an intimate knowledge of the visual tree of your application during the test run. You can glean this knowledge from the source code and mark-up if you have access to it, but this is tedious and as in our case you may not have access to the source code, testers often don’t. So you need a friendly tool to help you understand the visual tree and use more efficient find operations. Enter Silverlight Spy, I guarantee you will come to see this as an essential tool for testing and profiling Silverlight applications.
So fire up Silverlight Spy and navigate to http://pjd.mscui.net/PrimaryCare.htm you will see the MS CUI application hosted in the main window, where it will work as normal. The key difference is that Silverlight Spy has hooked into the visual tree of the application (among other things) and allows you to inspect it in the Explorer window. Now you could manually search through the visual tree for our target TextBlock but don’t waste your time. Make sure you have the Explorer pane activated, press Ctrl+Shift on your keyboard and move the mouse pointer over the text we are testing for:

The text is surrounded with a Red border and magically the User Interface node of the Explorer tree will expand and a TextBlock will be highlighted:

Silverlight Spy has just found the target object and navigated to it. Even a simple Silverlight application will have a fairly complex visual tree so remember this technique it will save you hours of tree trawling.
A couple of things to note. The highlighted TextBlock is not followed by a name in brackets as other some of of it’s near neighbours do, also if you look in the Properties sheet the AutomationId is blank so we can’t use either of these to find our TextBlock in tests. However if you work your way up the tree you will see the TextBlock has a parent StackPanel, which is the child of something labelled as PresenceNameLabel(userNameText). What is this? The format of nodes in the tree is Type[(name)] so what we are looking at is a custom control created by the MS CUI developers called a PresenceNameLabel and at the point where this control has been used it has been assigned a name of userNameText. We could use either of these to find this element and then it’s child TextBlock. Let’s explore both options by adding the following as the body of our test method:
1: var presenceNameLabel = App.Find.ByName("userNameText");
2: var textBlock = presenceNameLabel.Find.ByType("TextBlock");
In line 1 we are using the Find.ByName method to get a reference to custom control by it’s name, pretty straight forward.
In line 2 we are narrowing the scope of the find operation to children of the PresenceLabel custom control, but searching for it by type.
What both of these find operations return is an ArtOfTest.WebAii.Silverlight.FrameworkElement, which is a wrapper for the System.Windows.FrameworkElement and provides the basic functionality for UI automation, such as the Find object we are using in line 2.
To complete our test we want to make an assertion. We could use Assert.IsNotNull on textBlock but this isn’t really a valid test, we really need to test the actual content of it i.e. the Text property of the TextBlock element. As mentioned above what we have in the textBlock variable is a reference to a FrameworkElement, which has no knowledge of the Text property, what we really want is for our find operation to return us a strongly typed wrapper for the TextBlock. Fortunately this is quite easy, in the previous example I used the most basic versions of the Find.ByName and Find.ByType methods but there are also strongly typed versions that use Generics to ensure we get access to the richer functionality of wrappers. Unfortunately we aren’t ready to get a strongly typed PresenceNameLabel yet (we will deal with this in the next article) but we can make a simple change to our test method so that we get a strongly typed TextBlock and make an assertion against it’s Text property. Change the body of the test method to the following:
1: var presenceNameLabel = App.Find.ByName("userNameText");
2: var textBlock = presenceNameLabel.Find.ByType<TextBlock>();
3:
4: Assert.IsTrue(textBlock.Text.Contains("COX, Oliver (Dr)"));
In line 2 we specifying our target type as a Generic argument and what have now in textBlock is a reference to an ArtOfTest.WebAii.Silverlight.TextBlock that is aware of the Text property, which we use in a very simple assertions on line 4. I am not concerned whether the assertion is a good or bad one, just focus on the fact we can use a strongly typed object and code our tests using syntax that is similar to the development code.
For completeness here is the whole class so far:
1: using System;
2: using NUnit.Framework;
3: using ArtOfTest.WebAii.Silverlight.UI;
4:
5: namespace WebAii.Samples
6: {
7: [TestFixture]
8: public class GivenASuccessfulLogin: TestBase
9: {
10: [Test]
11: public void TheUsersNameIsDisplayed()
12: {
13: var presenceNameLabel = App.Find.ByName("userNameText");
14: var textBlock = presenceNameLabel.Find.ByType<TextBlock>();
15:
16: Assert.IsTrue(textBlock.Text.Contains("COX, Oliver (Dr)"));
17: }
18: }
19: }
Go ahead and run the test using your preferred test runner, it should pass. I use CodeRush and as you can see it passed for me:
Now I could go on and show you several other Find methods but I want to get you working with your own wrappers sooner rather than later so I am going end this article here, and move on to the next one where I will show you how to create wrappers that correspond to the custom controls that are present in the MS CUI and use them to make your tests more readable and your test code more re-usable.
Contains the sample solution including this new test. I have removed the test from the previous article as it was only to have something to run.