Automated Unit Testing of Silverlight 4 and 5 Applications

Requirements
Files
Author:
Applies to:
SmartBear Software
TestComplete 9 - 10 and Silverlight 4 or 5 (32- and 64- bit);
TestComplete 8.50-8.70 and Silverlight 4 (32-bit)

 

Introduction

This article describes how TestComplete can expose Silverlight applications and get access to their internal objects, their properties and methods. In the article, we explain how to perform automated unit testing of Silverlight applications with TestComplete.

The article also contains a sample Silverlight application and a TestComplete project that demonstrates how you can access applications’ internal classes and perform a simple unit test.

Note: The approach described in the article is applied to Silverlight 4 and 5 applications. Silverlight 2 and 3 are not supported since TestComplete 8.50. If your application was created with an earlier version of Silverlight, to be able to test it with TestComplete 8.50 and later, you need to rebuild it with the latest version of Silverlight.

You can also perform unit testing of Silverlight 3 applications with TestComplete 8 – 8.20 using the HTML Bridge technology (see Automated Unit Testing of Silverlight Applications with HTML Bridge for more information).

Basic Concepts

TestComplete 9 and 10 support testing of 32-bit and 64-bit Silverlight 5 code. TestComplete 8.50-8.70 supports testing of 32-bit Silverlight 4 applications only.

One of the main requirements for successful unit testing of Silverlight applications is the ability to get access to classes of Silverlight applications and to call methods and properties of these classes externally. This ability is provided by the TestComplete Web Module.

TestComplete exposes Silverlight controls and provides scriptable access to their public properties, fields and methods. Also, the plug-in provides the special SlApplication scripting object. Using its SlClasses property, you can obtain scriptable access from your tests to namespaces and classes declared in assemblies included in the Silverlight application package (in the .xap file).

Therefore, you can call Silverlight code from TestComplete scripts and keyword tests to perform unit testing of your Silverlight-based applications.

In the article, we will create unit tests right in a Silverlight application and then launch them from a TestComplete script to automate the tests. It is also possible to follow another approach and create all needed routines to perform unit testing right in TestComplete, not in the Silverlight application under test. You can create TestComplete scripts and keyword tests that will call the needed Silverlight code directly and test it.

Description of the Tested Object

We will consider a simple Silverlight application — NameExtractor. To download a sample project and source files for the sample application, use the hyperlinks from the menu in the top right corner of the page.

The application contains a class of the same name — NameExtractor. This class with its members is used as a tested object in our application. NameExtractor takes an input string containing an English/American proper name (i.e. “Mr. John Smith”) and then provides the ability to get separate name components extracted from this full name.

Let’s take a look at the definition of the class (not all members are shown below):

//C#

namespace NameExtractor
{
    class NameExtractor
    {
        public NameExtractor()
        { ... }

        public String FullName
        {
            get { ... }
            set { ... }
        }

        public String Title
        {
            get { ... }
        }
        public String FirstName
        {
            get { ... }
        }
        public String MiddleName
        {
            get { ... }
        }
        public String LastName
        {
            get { ... }
        }
        public String Suffix
        {
            get { ... }
        }

        ...

    }
 }

As you can see, the NameExtractor class contains a number of public properties. The FullName property takes an input full name. The Title, FirstName, MiddleName, LastName and Suffix read-only properties return the title, first name, middle name, last name and suffix part, correspondingly, extracted from the full name.

Also, there are a few private and protected properties and helper methods in the class. We will not give a full description of them here in the article, because we’d rather take an interest in testing the class and calling testing functions from TestComplete than in the implementation of the class to be tested. For the full implementation of the NameExtractor class, see the “NameExtractor.cs” source code file in the NameExtractor sample project.

In the next section we will discuss the UnitTestDriver class that is used to implement unit tests for our NameExtractor Silverlight class.

Creating Unit Tests

We will create unit tests for the NameExtractor class as methods of the UnitTestDriver class in the “UnitTestDriver.cs” source code file of our Silverlight project. Before creating the unit tests, we will implement a couple of helper methods in the UnitTestDriver class: the UnitTestDriver method is a constructor that creates an instance of the NameExtractor class to be tested by the UnitTestDriver class; the CheckEquals method compares two strings and throws an exception with the appropriate message if the strings are not equal. Here is the implementation of these methods:

// C#

namespace NameExtractor
{
    public class UnitTestDriver
    {
        //an object of the tested class NameExtractor
        private NameExtractor nameExtractor;

        public UnitTestDriver()
        {
            nameExtractor = new NameExtractor();
        }

        private void CheckEquals(String Expected, String Actual, String Msg)
        {
            if (Expected != Actual)
            {
                String exceptionMsg = String.Format("{0} : expected: {1}, but was: {2}", Msg, Expected, Actual);
                Exception exception = new Exception(exceptionMsg);
                throw exception;
            }
        }
    }
}

Now, we can add our unit tests for the NameExtractor object to the UnitTestDriver class. For simplicity, we will implement two unit tests that will check two business rules of the tested object: the Test1 method checks whether the NameExtractor object can break the full name into a word list, and the Test2 method checks whether the words in the list have a strict order (the Title, the First Name, the Middle Name, the Last Name and the Suffix). For more information on the business rules defined for the NameExtractor tested object, see the Unit Testing - TestComplete Example article.

// C#

//tests
public void Test1()
{
    nameExtractor.FullName = "Mr John Greench Brown, PhD";
    CheckEquals("Mr", nameExtractor.Title, "Title is not correct");
    CheckEquals("John", nameExtractor.FirstName, "First Name is not correct");
    CheckEquals("Greench", nameExtractor.MiddleName, "Middle Name is not correct");
    CheckEquals("Brown", nameExtractor.LastName, "Last Name is not correct");
    CheckEquals("PhD", nameExtractor.Suffix, "Suffix is not correct");
}

public void Test2()
{
    nameExtractor.FullName = "John Brown";
    CheckEquals("", nameExtractor.Title, " Title is not correct");
    CheckEquals("John", nameExtractor.FirstName, " First Name is not correct");
    CheckEquals("", nameExtractor.MiddleName, " Middle Name is not correct");
    CheckEquals("Brown", nameExtractor.LastName, " Last Name is not correct");
    CheckEquals("", nameExtractor.Suffix, " Suffix is not correct");

    nameExtractor.FullName = "Mr. John Brown";
    CheckEquals("Mr", nameExtractor.Title, " Title is not correct");
    CheckEquals("John", nameExtractor.FirstName, " First Name is not correct");
    CheckEquals("", nameExtractor.MiddleName, " Middle Name is not correct");
    CheckEquals("Brown", nameExtractor.LastName, " Last Name is not correct");
    CheckEquals("", nameExtractor.Suffix, " Suffix is not correct");

    nameExtractor.FullName = "John Brown, PhD";
    CheckEquals("John", nameExtractor.FirstName, " First Name is not correct");
    CheckEquals("Brown", nameExtractor.LastName, " Last Name is not correct");
    CheckEquals("PhD", nameExtractor.Suffix, " Suffix is not correct");
}

Now, when you have a class to be tested and a class that will perform testing of the first one, you can access managed code of your Silverlight application from TestComplete scripts or keyword tests.

Preparing a Silverlight Application for Unit Testing

Exposing an Application's Internals to TestComplete

TestComplete can access internal objects, properties and methods of Silverlight 4 and 5 applications under test. In TestComplete terms, these applications are “Open” to the test engine.

In order for TestComplete to be able to treat your Silverlight application as Open, the application must meet the following requirements:

  • It must be run in the Internet Explorer or Mozilla Firefox web browser.

    Note:Support for testing Silverlight applications in Mozilla Firefox was discontinued in TestComplete 9.30.

  • The application’s wrapper web page must load the application packager .xap file directly from the server (TestComplete cannot make the application Open if it is loaded from the browser cache).
  • The application wrapper object must be loaded via the HTTP protocol.

If one of these requirements is not met or your application does not become open for some other reason, TestComplete will not be able to access the application’s internals and their properties and methods.

In that case, to make your application open, you need to prepare it for testing by processing it with the tcAgPatcher.exe command-line utility shipped with TestComplete.

The utility resides in the <TestComplete>\Open Apps\Silverlight folder. The fully-qualified name of the .xap package file in which the application is implemented is passed to the utility through its command-line parameters.

The utility processes the .xap file and integrates helper libraries into it. The libraries serve as a bridge between TestComplete and the application under test and allow TestComplete to obtain access to internal objects of the application.

The NameExtractor application we use as an example in the article is not treated by TestComplete as open as the .xap application file is loaded by the wrapper object from a local folder, not from a web server. To make the application open and access its internal objects and their properties and methods, we process the application with the tcAgPatcher utility:

tcAgPatcher.exe “C:\MyProjects\NameExtractor\Bin\Debug\NameExtractor.xap”

Then we replace the original NameExtractor.xap file with the processed one. All public members of UnitTestingDriver and other classes become accessible from scripts and keyword tests.

You can find more information on preparing your Silverlight applications for testing with the tcAgPatcher.exe utility in the Preparing Silverlight Application for Testing topic of the TestComplete online help.

Preparing an Application for Testing in Firefox

If you use Firefox, you need to configure your application so that it runs in the windowless mode and the Firefox Silverlight plug-in must run in the out-of-process mode. For information on how to prepare your application for testing in Firefox, see Preparing Silverlight Application for Testing in the TestComplete help.
Note: Testing of Silverlight applications in Firefox is not supported in TestComplete 10. You can test them in Internet Explorer.
In the article, we will use Internet Explorer, so we do not have to configure our sample application in any special way.

Calling Silverlight Code from TestComplete to Perform Unit Testing

Now, let’s run unit tests we created earlier. Since we have scripting access to the Test1 and Test2 methods of the UnitTestDriver class of the sample Silverlight application, we can call these methods from TestComplete scripts and keyword tests. This allows you to perform unit testing of our NameExtractor Silverlight-based application with TestComplete. Let’s take a look at how you can perform this testing.

Open the web page holding the application in a web browser (we use Internet Explorer). Now, you need to find a web object that corresponds to our Silverlight application in the Object Browser’s Object Tree in order to communicate with the application from TestComplete.

For this purpose, you can use the Object Spy window of TestComplete. Select  Object Spy from TestComplete's Tools toolbar to display the window. Using the Finder tool (the Finder tool glyph in the top left corner of the window), select the needed object in the web browser’s window as it is illustrated on the image below:

Selecting the web object that corresponds to the Silverlight application

Figure 1 – Selecting the web object that corresponds to the Silverlight application

Then, in the FullName property of the selected object, you can see the Object Tree path to the object. This property is displayed in the Object Spy window after you selected the object with the Finder tool if the Advanced view mode is activated in the Object Spy window. To activate this mode, click the View more members (Advanced view) link at the top of the Properties page of the Object Spy window. In this case, the window will look like it is shown in the image below:

Exploring the path to the object via the Object Properties window

Figure 2 – Exploring the path to the object via the Object Spy window

In our case, the Object Tree path to the web object is as follows:

// JScript

Sys.Browser("iexplore").Page("file:///C:/MyProjects/NameExtractor/Bin/Debug/NameExtractorTestPage.html").Form("form1").Panel("silverlightControlHost").Object(0);

Note: We explore our application in TestComplete 10. TestComplete 9 represents browser objects in a similar way. In TestComplete 8.x and earlier versions, there will be Sys.Process(“iexplore”) instead of Sys.Browser(“iexplore”).
Note also that the path may differ in your own Silverlight applications.

Let’s create a helper script routine that will return an object corresponding to our Silverlight application in a TestComplete script:

// JScript

function GetSlObject()
{
    return Sys.Browser(“iexplore”).Page("file:///C:/MyProjects/NameExtractor/Bin/Debug/NameExtractorTestPage.html").Form("form1").Panel("silverlightControlHost").Object(0);
}

The object returned by this routine contains the SlApplication method that returns an object with the same name. This SlApplication program object is a wrapper to the Silverlight application’s main class that encapsulates application-specific functionality. The SlApplication object is shown in the Object Tree as a child object of the web object corresponding to our Silverlight application (the object returned by the GetSlObject script routine which we have declared above).

SlApplication contains the SlClasses property that provides access to all namespaces defined in the assemblies included in the Silverlight application package. For each namespace, an object returned by SlClasses provides an appropriate property. Using these properties you can access classes declared in the appropriate namespaces of the tested Silverlight application. For instance, you can call static public methods and properties of these classes or even create class instances directly in your tests by calling constructors of the needed classes.

The UnitTestDriver class that contains the implementation of our unit tests is defined in the NameExtractor namespace. So, you can access the class by using the SlApplication.SlClasses.NameExtractor.UnitTestDriver code snippet. Since this class and its methods are non-static, we need first to create an instance of the class in our TestComplete test before calling methods of the class. If you explore the members of the UnitTestDriver class in the Object Browser or in the Object Spy window of TestComplete, you will not see the Test1 and Test2 methods in the list of the class methods, because these two methods are non-static.

To create a UnitTestDriver object, call the class constructor. The name of the constructor to be called from your script code is zctor (TestComplete names all .NET class constructors like this). To create an instance of the UnitTestDriver class, you can write the following code in your TestComplete script:

// JScript

var slObject = GetSlObject();

var unitTestDriver = slObject.SlApplication.SlClasses.NameExtractor.UnitTestDriver.zctor();

Now, since we have created the program object needed to perform unit testing of our NameExtractor application, we can call the object’s testing methods - Test1 and Test2. For instance, we can launch unit tests from a TestComplete script in the following way:

// JScript

function Main()
{
    var slObject = GetSlObject();
    var unitTestDriver = slObject.SlApplication.SlClasses.NameExtractor.UnitTestDriver.zctor();
    Test1(unitTestDriver);
    Test2(unitTestDriver);
}

function Test1(unitTestDriver)
{
    try
    {
        unitTestDriver.Test1();
        Log.Message("Test1 passed.");
    }
    catch(ex)
    {
        Log.Error("Test1 failed.", ex.description);
    }
}

function Test2(unitTestDriver)
{
    try
    {
        unitTestDriver.Test2();
        Log.Message("Test2 passed.");
    }
    catch(ex)
    {
        Log.Error("Test2 failed.", ex.description);
    }
}

The Main function in the script above creates the unitTestDriver scriptable object (an instance of the UnitTestDriver class) and then calls the Test1 and Test2 helper script functions one-by-one. Each function gets the unitTestDriver object passed through the function’s parameter and calls the appropriate method of the object to perform unit testing. The calls to the Test1 and Test2 methods of the unitTestDriver object are enclosed in the try … catch statements in order to handle possible errors that may occur during the test execution. So, if the test execution fails due to any errors in the test or in the code being tested, TestComplete posts an appropriate message to the test log:

Error message in the test log

Figure 3 – Error message in the test log

Then, you can view the test log and make decisions on how the tested Silverlight code works and whether it needs any changes and improvements.

In our example, we have created unit tests right in a Silverlight application (in its UnitTestDriver class) and then launched them from a TestComplete script to automate the tests. We would like to remind that TestComplete has scriptable access to all public classes and their members defined in the Silverlight application that was processed with the tcAgPatcher utility. Therefore, you can create needed routines to perform automated unit testing right in TestComplete, not in the tested Silverlight application. You can create TestComplete scripts or keyword tests that will directly call the needed Silverlight code and test it.

Conclusion

In this article, we have explained how you can get access to internal objects, methods and properties of your Silverlight 4 and 5 applications from TestComplete tests. We hope this information will help you test and improve your Silverlight applications with unit testing and TestComplete. If you haven’t used the latest version of TestComplete yet, try it for free today.