Recommended

  • Silverlight.FX
    Silverlight.FX is a light-weight application framework for building RichInternet Applications with Silverlight 2.
  • Building Modular Silverlight Applications
  • .NET RIAServices - Building Data-Driven Applications with Microsoft Silverlight andMicrosoft ASP.NET
  • Securing Silverlight Application and WCF Service using ASP.Net Authentication Techniques
  • Model– View – ViewModel in Silverlight

Skip Navigation LinksHome / Articles / View Article

Silverlight Testing - Part 1 - Testing the untested.

+ Add to SilverlightShow Favorites
1 comments   /   aggregated from Eric Hexter on Apr 21, 2008  /  original article
(0 votes)
Categories: Tutorials , Misc
The Silverlight testing framework was recently released and shows some great potential for being
a first class application platform. For more information about the test framework see this post from
Jeff Wilcox.
To start off I choose to use a code sample that had some complexity in it.  Brad Abrams just posted 
a Silverlight walk
End-to-End Data Centric Application with Silverlight 2. This seemed like a good
sample to use, since the post did not consider how to test the code.
Step 1:  Add a test project and test class. 
After the installing the assemblies and project templates, add a new unit test project to the solution.
Change the test class to inherit from SilverlightTest.
The following code demonstrates a simple integration test.
This test does the following: 
  • Instantiates the page.
  • Clears the local storage.
  • Adds the page to the Test framework TestSurface.
  • Enters the letter s into the text box.
  • Clicks the search button.
  • Verifies that 9 products are displayed in the DataGrid.
  • Removes the page from the TestSurface.

Here is the code for the test class:
   1:      [TestClass]
   2:      public class The_data_page_should_load:SilverlightTest
   3:      {
   4:          
   5:          [TestMethod]
   6:          public void When_searching_for_products_starting_with_s_nine_products_should_be_displayed()
   7:          {
   8:              EndToEndSilverlightDemo.Page pageUnderTest = new EndToEndSilverlightDemo.Page();
   9:              IPageTestDriver testDriver = pageUnderTest;
  10:              testDriver.ClearLocalStorage();
  11:              this.Silverlight.TestSurface.Children.Add(pageUnderTest);
  12:              testDriver.TypeSearchPrefix("s");
  13:              testDriver.ClickSearchButton();
  14:              Assert.AreEqual(9,testDriver.DisplayedProductRows);
  15:              this.Silverlight.TestSurface.Children.Remove(pageUnderTest);
  16:          }
  17:      }
 
Here is the Test Driver interface:
   1:  public interface IPageTestDriver
   2:     {
   3:         void TypeSearchPrefix(string searchPrefix);
   4:         void ClickSearchButton();
   5:         int DisplayedProductRows { get; }
   6:         void ClearLocalStorage();
   7:         bool WebserviceHasReturnedData();
   8:     }
Here is the portions of the Page class that implement the IPageTestDriver interface. It is a good idea to 
hide the complexity of the Page classes internal controls from the test class. This is equivalent to
creating a Test Fixture in other frameworks.

   1:          void IPageTestDriver.TypeSearchPrefix(string searchPrefix)
   2:          {
   3:              this.txtProductString.Text = searchPrefix;
   4:          }
   5:   
   6:          void IPageTestDriver.ClickSearchButton()
   7:          {
   8:              this.Button_Click(this.btnOne,null);
   9:          }
  10:   
  11:          int IPageTestDriver.DisplayedProductRows
  12:          {
  13:              get { return (new List<object>((IEnumerable<object>) this.dataGridResults.ItemsSource)).Count; }
  14:          }
  15:   
  16:          void IPageTestDriver.ClearLocalStorage()
  17:          {
  18:              settings.Clear();
  19:              settings.Save();
  20:              dataGridResults.ItemsSource = null;
  21:          }
  22:   
  23:          bool IPageTestDriver.WebserviceHasReturnedData()
  24:          {
  25:              return dataGridResults.ItemsSource != null;
  26:          }
  27:      }
 
Now run the test and everything is good right?  Not so.  But why is that?


The test has failed because the application is making an Asynchronous call to the web service.  This means
our test runs and completes before the remote call to return data can complete and load the data into the data grid.
 

Solution:  Use the Asynchronous features of the test framework.

The framework provides the functionality to be able to drive unit tests in an async fashion.  This allows the
test to run and wait for a condition to be met before proceeding.  In this case on line 10 the EnqueueConditional
call waits until the helper method returns true before the test proceeds with the next call.
   1:          [TestMethod,Asynchronous]
   2:          public void When_searching_for_products_starting_with_s_nine_products_should_be_displayed_async()
   3:          {
   4:              EndToEndSilverlightDemo.Page pageUnderTest = new EndToEndSilverlightDemo.Page();
   5:              IPageTestDriver testDriver = pageUnderTest;
   6:              testDriver.ClearLocalStorage();
   7:              this.Silverlight.TestSurface.Children.Add(pageUnderTest);
   8:              EnqueueCallback(() => testDriver.TypeSearchPrefix("s"));
   9:              EnqueueCallback(() => testDriver.ClickSearchButton());
  10:              EnqueueConditional(testDriver.WebserviceHasReturnedData);
  11:              EnqueueCallback(() => Assert.AreEqual(9, testDriver.DisplayedProductRows));
  12:              EnqueueCallback(() => this.Silverlight.TestSurface.Children.Remove(pageUnderTest));
  13:              EnqueueTestComplete();
  14:          }
 
And the results?....

The test passes and verifies the full remote call to the web service as well as getting the data back into the user interface.
Pretty cool?  This sample demonstrates that it is possible to test drive the user interface.  The code to do so is far from
being readable and comprehendible.  The next post in this series will address the readability of the testing code and put a
fluent interface around the ugly Enqueue method calls. 

 

The source code for this sample is available here; http://erichexter.googlecode.com/svn/trunk/EndToEndSilverlightDemo/EndToEndSilverlightDemo/ 

Share


Comments

Comments RSS RSS
  • RE: Silverlight Testing - Part 1 - Testing the untested.  

    posted by Stephen Price on Apr 08, 2009 12:23
    Not looked at this closely, but if you have EnqueueConditional on your testdriver.WebserviceHasReturnedData and it failed, wouldn't the itemsSource be null and thus wait forever? (I don't think the Enqueue has a timeout does it?)
    just a thought..
    thanks for the post!
    Stephen Price

Add Comment

 
 

   
  
  
   
 Refresh