in

 

Eric Hexter

Where the rubber meets the road.

April 2008 - Posts

  • Silverlight Testing - Part 2 - Making the test easier understand.

    Now that we have a working test that can make the proper assertions, the next step is to make the test easier to understand.  First, here is the existing test.

    FluentUiTest

    The test is loaded with infrastructure code that helps execute the asynchronous calls with the testing framework. This does not help the readability of the tests.  More than half of the code in this methods are helper methods and plumbing.  This is far from ideal.  Another approach to this would be to use a fluent interface that abstracts the plumbing code and leaves a test that is easier to comprehend.

     

    FluentUiTest

    In this code you will see the UiTestHelper class which hides more of the magic EnqeueXXXX calls to the SilverlightTest base class. This class also hides the code needed to add/remove the control to the test surface as well as call the TestComplete method.  This approach is less complicated and as a result allows for easier comprehension when you need to come back and change the code or the tests later in the project.  The tests are doing the exact same work and making the same assertion. 

     

    Subscribe to this feed: http://feeds.feedburner.com/erichexter

     

    The code for this project is located here : http://erichexter.googlecode.com/svn/trunk/EndToEndSilverlightDemo

  • 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/ 

  • Silverlight Testing framework bug - FrameworkElements are not visible on the TestSurface

    Working with the Silverlight testing framework the last three weeks has been interesting.  I ran into a crazy intermittent bug which drove me made for about 2 hours.  The usercontrol that I was adding to the TestSurface would be visible about 50% of the time when running my tests. The test would still run and I could hear the audio portion of the videos that were playing as part of an integration test, but the Controls were not visible on the test surface. All I could see was the blank test surface and the testing framework status on the right side of the test runner.

     
    After resorting to reflector on the test framework I found that the TestSurface is a Grid control.  That got me to think that since my controls parent control is also a Grid control that maybe the nested grids are just having some sort of issue.  I ended up solving the problem by Adding my controls to a Canvas control and adding the Canvas instance to the TestSurface.  Code as follows......


    Subscribe to this feed: http://feeds.feedburner.com/erichexter 

    si-testing-testsurfacebug

     

    This solved my problem... The issue is not with the test framework as much as the silverlight runtime.  It is still beta so what do you expect?

    More posts on the test framework, both unit testing and integration testing, to come soon.

     

    Additional Info: 

    For more information about the silverlight testing framework see: http://www.jeff.wilcox.name/2008/03/31/silverlight2-unit-testing/

  • ASP.Net MVC framework - New version of the MVC Contrib project! - v 0.0.1.101

    There was a new source code release of the Asp.Net MVC framework .  We just got the MVC Contrib project upgraded to work against the new release.

    You can find the release here.

     

    First I would like to thank Jeremy Skinner for his hard work upgrading the release!

     

    Here is what changed in the release:

    • Upgraded to the 0416 Source Code drop of ASP.NET MVC.
    • Moved most of ConventionController's logic into ConventionControllerActionInvoker.
    • ControllerDescriptor now only treats methods that return an ActionResult as a valid action.
    • Moved the filters implementation more in line with the implementation in ControllerActionInvoker.
    • Removed the ReturnBinders implementation. The same result can be achieved by using custom ActionResults.
    • Introduced XmlResult to replace XmlReturnBinder.
    • Added RenderText and RenderXML methods to ConventionController.
    • TestControllerBuilder no longer proxies controllers or captures renderview/redirect calls

     

    Keep up to date by subscribing to http://feeds.feedburner.com/EricHexter

     

    Do you twitter?  You can follow the project on twitter here: http://twitter.com/mvccontrib

Copyright Los Techies 2007. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems