Silverlight Testing – Part 1 – Testing the untested.

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?


sl-test-failed


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?….

sl-test-passed

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/ 


Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Eric Hexter

I am the CTO for QuarterSpot. I (co)Founded MvcContrib, Should, Solution Factory, and Pstrami open source projects. I have co-authored MVC 2 in Action, MVC3 in Action, and MVC 4 in Action. I co-founded online events like mvcConf, aspConf, and Community for MVC. I am also a Microsoft MVP in ASP.Net.
This entry was posted in c#, silverlight, testing. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.lostechies.com/blogs/joe_ocampo/ Joe Ocampo

    This is really awesome to see a Test Framework for such a new technology. Very promising for silverlight’s future as a first class web platform.

  • http://blogs.msdn.com/brada Brad Abrams

    This is great! thanks for adding the testing support.. you made the sample much better