Requirements
Files

Author: SmartBear Software
Applies to: TestComplete 7 - 8.20 and Silverlight 3

Introduction

In this article, we explain how to perform unit testing of Silverlight applications with TestComplete using the HTML Bridge technology. The article describes how to use the technology to make the application’s classes and their members accessible to TestComplete during the unit testing.

The article also contains a simple example of a Silverlight application and a sample TestComplete project that demonstrates how to perform automated unit testing.

Note: We discontinued support for Silverlight 2 and 3 since TestComplete 8.50. To be able to test your applications with newer versions of TestComplete, rebuild them with later version of Silverlight.

Note that since version 8.50, TestComplete automatically exposes Silverlight applications’ internal objects and their members and can access them from tests. In other words, to perform unit testing of Silverlight applications, you do not have to expose application internals with the HTML Bridge technology. For information on unit testing of Silverlight applications with TestComplete 8.50 - 9, see Automated Unit Testing of Silverlight Applications.

Basic Concepts

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 capability is provided by the HTML Bridge technology that lets you call Silverlight managed code from a client JavaScript code located in a web page. Therefore, by using this technology, you can also call Silverlight code from TestComplete scripts and perform unit testing of your Silverlight-based applications.

In order to make Silverlight classes and their members accessible to scripts, HTML Bridge provides the ScriptableType and ScriptableMember attributes used for making the needed Silverlight data types and members available to scripts. Also, the needed Silverlight class must be registered as a scriptable object with the use of the HtmlPage.RegisterScriptableObject method.

Note that HTML Bridge is a documented technology and you can find additional information about it in the MSDN Library.

Description of the Tested Object

We will consider a simple Silverlight application — NameExtractor. To download a sample project, 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 external script code from TestComplete scripts.

Preparing Silverlight Code for Unit Testing

As stated above, we will test the NameExtractor class via the UnitTestDriver helper class. So, we need to make the UnitTestDriver class accessible from scripts in order to run unit tests from TestComplete. This is where the HTML Bridge technology will help you in your unit testing. We need to perform the following steps:

  1. Register a Silverlight class as a script object by using the HtmlPage.RegisterScriptableObject method (in our case, we will provide scriptable access to the methods of the UnitTestDriver class).
  2. Mark the whole class or certain members as script objects by using the ScriptableTypeAttribute or ScriptableMemberAttribute attributes.

In order to use a class outside of a Silverlight application, you should create an instance of the class and register it as a scriptable type (see the MSDN Library for detailed information). You can do this by calling the HtmlPage.RegisterScriptableObject method, provided by the HTML Bridge. It is recommended to call this method upon startup of your Silverlight application so that the class can be accessible from scripts when your application is running. For instance, you can call this method from the body of the Application_Startup method of the App class. This class encapsulates your Silverlight application and the Application_Startup method is the Startup event handler that performs initialization of the application. Open the “App.xaml.cs” source code file that contains the implementation of the App class in the NameExtractor project and modify the Application_Startup method in the following way:

// C#

private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new MainPage();
HtmlPage.RegisterScriptableObject("unitTestDriver", new UnitTestDriver());
}

This code creates an instance of the UnitTestDriver class and registers it as a scriptable object with the unitTestDriver name upon the application’s startup. Now, you can use the unitTestDriver script object in client scripts of your Silverlight application.

However, more is needed to call the object’s methods, properties and events from outside of your Silverlight application. First, you can use only public members of your Silverlight class in a script. Furthermore, you must specify which members of the class will be accessible in scripts. For this purpose, HTML Bridge provides two special attributes — System.Windows.Browser.ScriptableTypeAttribute and System.Windows.Browser.ScriptableMemberAttribute. You can mark the UnitTestDriver class with the ScriptableTypeAttribute attribute:

// C#

using namespace System.Windows.Browser;

namespace NameExtractor
{
[ScriptableType] //Provides scriptable access to the entire class
public class UnitTestDriver
{

}
}

In this case, all public members of UnitTestDriver will be accessible from scripts. If you do not want to provide scriptable access to all public members of your class, you can mark only the needed members with the ScriptableMemberAttribute attribute. We will use this approach in our sample application to provide scriptable access to the Test1 and Test2 methods of the UnitTestDriver class:

// C#

using namespace System.Windows.Browser;
namespace NameExtractor
{
public class UnitTestDriver
{

//tests
[ScriptableMember] //Provides scriptable access to Test1
public void Test1()
{

}

[ScriptableMember] //Provides scriptable access to Test2
public void Test2()
{

}
}
}

It should be noted that the ScriptableMemberAttribute attribute only makes sense for public class members.

Calling Silverlight Code from TestComplete Unit Tests

Since we have provided scriptable access to the Test1 and Test2 methods of the UnitTestDriver class, we can call them from scripts of a web page holding our Silverlight application, and above all — from TestComplete scripts, too. 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.

Build the application and open the resulting web page holding your Silverlight sample application in a web browser. 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 at the bottom 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 and is only available in the Advanced view mode. To activate this mode click the View more members (Advanced view) link at the top of the Object Spy window. In this case the window will look like it is shown on 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 the following:

// JScript
Sys.Process("IEXPLORE", 2).Page("file:///C:/MyProjects/NameExtractor/Bin/Debug/TestPage.html").Form("form1").Panel("silverlightControlHost").Object(0)

Note 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.Process("IEXPLORE", 2).Page("file:///C:/MyProjects/NameExtractor/Bin/Debug/TestPage.html").Form("form1").Panel("silverlightControlHost").Object(0);
}

The object returned by this routine contains the Content property that provides access to the registered scriptable objects of the tested Silverlight application. Using the Content.unitTestDriver code snippet, we can get access to the unitTestDriver scriptable object which we have registered earlier with the HtmlPage.RegisterScriptableObject method (see the Preparing Silverlight Code for Unit Testing section above in this article) and then use this object for unit testing of the application. In your TestComplete script, you can write the following code to obtain the unitTestDriver object:

// JScript

var slObject = GetSlObject();
var unitTestDriver = slObject.Content.unitTestDriver;

Note that the name of the property which we get from the Content object is unitTestDriver, not UnitTestDriver. That is, we use the name passed through the first parameter of the HtmlPage.RegisterScriptableObject method when we called this method to register the UnitTestDriver class as the unitTestDriver scriptable object.

Now, since we have retrieved the object needed for performing the unit testing of our NameExtractor application, we can call the object’s testing methods — Test1 and Test2 (we have marked these methods as scriptable members of the UnitTestDriver class). For instance, we can launch unit tests from a TestComplete script in the following way:

// JScript

function Main()
{

var slObject = GetSlObject();
var unitTestDriver = slObject.Content.unitTestDriver;
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 obtains the unitTestDriver scriptable object corresponding to the tested Silverlight application 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 the Silverlight application and then launched them from a TestComplete script to automate the tests. Note that with the described HTML Bridge technology you can make not only specific testing routines in your Silverlight application scriptable, but you can also provide scripting access to the entire class and to all its members in the same way as described above. In this case, you can create your automated unit tests right in TestComplete, not in the tested Silverlight application.

Conclusion

In the article, we have given an overview of the HTML Bridge technology that makes Silverlight objects and their members accessible to TestComplete’s test engine. We have explained how to use the HTML Bridge technology to get access to internal code of your Silverlight application from TestComplete scripts and create automated unit tests for Silverlight applications.

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, download and try it for free.