Code Driven UI Testing

,

A key benefit of the MVVM pattern is that it allows you to unit test an app without needing to display its UI. Sometimes, however, you may want to verify the behavior of the UI by emulating user interaction. This can be achieved using coded UI tests.

The advantage of coded UI tests is that they provide your app with a test environment that is closer to the real world; they allow you to simulate the tapping of buttons or entering of text while the app is running.

The downside of coded UI tests is that they are tightly coupled to the user interface, which is often the most likely thing to change over time. If the UI is modified, it can mean having to rewrite your coded UI tests.

Coded UI tests can be performed with the UTF by populating a test Panel control that can host UIElements during test execution. The PresentationTest class subclasses the WorkItemTest class and provides a TestPanel property that allows you to materialize the page or control that you want to test. Observe the following excerpt:

[TestClass]
public class ChatClientUITests : PresentationTest
{
    ChatClientView view;

    [TestInitialize]
    public void PreparePage()
    {
        view = new ChatClientView();
        TestPanel.Children.Add(view);
    }
...
}

Recall that the TestInitialize attribute causes the method to be called before each test method in the parent class. When the PreparePage method is called, it creates a new instance of the ChatClientView and places it into a container control within the test harness.

This section looks at the three test methods in the ChatClientUITests class.

The first test method simply verifies that the PhoneApplicationPage is presented in the TestPanel, as shown:

[TestMethod]
public void ShouldDisplayDefaultSize()
{
    Assert.IsTrue(view.ActualWidth > 0);
}

The ShouldDisplayDefaultSize method demonstrates that you are able to interact with the UI elements from code. In fact, while the tests are running, their actions are viewable within the test harness (see Figure 24.7).

Image

FIGURE 24.7 A UI test in execution.

To interact with controls on the page, give the test project access to the internal members of the main project. This is done by placing an InternalsVisibleTo attribute in the AssemblyInfo class of the main project, shown in the previous section “Testing Nonpublic Members.”

When the InternalsVisibleTo is placed in the target project, IntelliSense is enabled for controls on the page.

To test that the Send button is enabled when the message TextBox is populated, set the text and then perform an assert using the button, as shown in the following excerpt:

[TestMethod]
public void ButtonShouldBeEnabled()
{
    view.textBlock_Message.Text = "Test";
    Assert.IsTrue(view.button_Send.IsEnabled);
}

Asynchronous Testing

The UTF is designed to run tests on a single thread. The UI thread in Windows Phone XAML apps uses a message pump, and often calls to update properties or reactions to property changed events are driven forward using Dispatcher calls. The result is that a UIElement may not be in the state that you think it should be when you are performing an assertion. Fortunately the Windows Phone UTF compensates with some built-in asynchronous features.

The Asynchronous attribute tells the UTF to keep running the test until the test class’s base method, WorkItemTest.EnqueueTestComplete, is called, or until an unhandled exception occurs. This allows you to spin off work to other threads, or queue work to happen on the UI thread, while keeping the test alive.

The WorkItemTest.EnqueueCallback method allows actions to be queued on the UI thread. This may include actions such as verifying the value of a UIElement’s property after a PropertyChanged event has been given the opportunity to propagate.

The following excerpt demonstrates how to use the Asynchronous attribute in combination with the EnqueueCallback method to set the text of a sample view’s message box. It simulates a tap to the Send Message button and then verifies that the ListBox has been correctly populated:

[TestMethod]
[Asynchronous]
public void ButtonShouldSendMessage()
{
    view.textBlock_Message.Text = "Test";
    EnqueueCallback(() => ((IAppBarItem)view.button_Send).PerformClick());
    EnqueueCallback(() => Assert.IsTrue(view.listBox.Items.Count > 0));
    EnqueueTestComplete();
}

When the textBlock_Message.Text property is set, the Send button is not enabled until the viewmodel’s SendCommand responds to the Message property’s PropertyChanged event. After it has had a chance to respond, the command enables itself.

The EnqueueCallback method queues the PerformClick method, so that by the time it is called, the button is enabled. Similarly, verification that the ListBox has been populated must occur after the UI has responded to the new item in the Messages collection in the viewmodel.

The UTF is notified that all nonblocking activity has been completed by calling the base class’s WorkItemTest.EnqueueTestComplete method.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.56.28