Outputting Visual Studio Logs from Silverlight Unit Test Framework

After much tearing of my hair out trying to understand how the Silverlight Unit Testing framework can output Visual Studio Test Result files (TestResults.trx), I have come up with the simplest solution I could think of, that I’m sure anyone can follow:

Setting up the Silverlight Unit Test Project

  1. Create a new Silverlight Application project in Visual Studio and add the following references:
    • Microsoft.Silverlight.Testing
    • Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight
  2. Add the following code to the Application_Startup function in App.xaml.cs:
  3. Code Snippet
    1. private void Application_Startup(object sender, StartupEventArgs e)
    2. {
    3.     var settings = UnitTestSystem.CreateDefaultSettings();
    4.     settings.TestService.UniqueTestRunIdentifier = Guid.NewGuid().ToString();
    5.     this.RootVisual = UnitTestSystem.CreateTestPage(settings);
    6. }

The Silverlight test project is now ready to have test classes added to it.

Setting up the Log Handler Web Service

The Silverlight’s Unit Testing Framework test runner has an in-built VisualStudioLogProvider that is automatically configured to output to http://localhost:8000/externalInterfaces

To support accepting the log content, you’ll need to create a special web site or Http Service to listen on this port, at this address. Stupidly this not configurable (yet), of course you could possibly implement your own logging service (and if you do I wish you luck).

The easiest way I could think of accepting the information and providing the correct responses for the TestHarness was to create an ASP.NET MVC web site.

  1. Create a new C# ASP.NET MVC web application
  2. Right click the ASP.NET MVC project, select the Web tab and change the development server to host on a specific port: 8000

    image

  3. Add a file called clientaccesspolicy.xml to the root of the web site and add the following xml to it:
  4. Code Snippet
    1. <?xml version="1.0" encoding="utf-8" ?>
    2. <access-policy>
    3.     <cross-domain-access>
    4.         <policy>
    5.             <allow-from http-request-headers="*">
    6.                 <domain uri="*"/>
    7.             </allow-from>
    8.             <grant-to>
    9.                 <resource path="/"
    10.                           include-subpaths="true"/>
    11.             </grant-to>
    12.         </policy>
    13.     </cross-domain-access>
    14. </access-policy>

  5. Add the following code to the RegisterRoutes function in the Global.asax.cs file:
  6. Code Snippet
    1. public static void RegisterRoutes(RouteCollection routes)
    2. {
    3.     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    4.  
    5.     routes.MapRoute(
    6.         "Default",                              // Route name
    7.         "{controller}/{action}/{*pathInfo}",    // URL with parameters
    8.         new
    9.         {
    10.             controller = "Home",
    11.             action = "Index",
    12.             pathInfo = ""
    13.         }  // Parameter defaults
    14.     );
    15. }

  7. Create a new controller under the \Controllers folder called ExternalInterfacesController.cs
  8. Add the following code to the controller:
  9. Code Snippet
    1. public class ExternalInterfaceController : Controller
    2. {
    3.     [AcceptVerbs(HttpVerbs.Get)]
    4.     public ActionResult Ping()
    5.     {
    6.         return View();
    7.     }
    8.  
    9.     [AcceptVerbs(HttpVerbs.Get)]
    10.     public ActionResult GetRunParameters(string pathInfo)
    11.     {
    12.         return View();
    13.     }
    14.  
    15.     [AcceptVerbs(HttpVerbs.Get)]
    16.     public ActionResult ReportTestResults(string pathInfo)
    17.     {
    18.         return View();
    19.     }
    20.  
    21.     [ValidateInput(false)]
    22.     [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
    23.     public ActionResult SaveLogFile(string pathInfo)
    24.     {
    25.         var fileName = pathInfo.Split(‘/’).SkipWhile(part => !part.StartsWith("logName")).Skip(1).FirstOrDefault();
    26.         if (!string.IsNullOrEmpty(fileName))
    27.         {
    28.             this.Request.SaveAs(Server.MapPath(Path.Combine(@"\App_Data", fileName)), false);
    29.         }
    30.  
    31.         return View();
    32.     }
    33.  
    34.     protected override void Execute(System.Web.Routing.RequestContext requestContext)
    35.     {
    36.         // HACK: To overcome Http Form Validation (ValidateInput attribute doesn’t seem to work).
    37.         string pathInfo = requestContext.HttpContext.Request.Url.PathAndQuery;
    38.         if (pathInfo.StartsWith("/externalInterface/saveLogFile/", StringComparison.OrdinalIgnoreCase))
    39.         {
    40.             var fileName = pathInfo.Split(‘/’).SkipWhile(part => !part.StartsWith("logName")).Skip(1).FirstOrDefault();
    41.             if (!string.IsNullOrEmpty(fileName))
    42.             {
    43.                 requestContext.HttpContext.Request.SaveAs(requestContext.HttpContext.Server.MapPath(Path.Combine(@"\App_Data", fileName)), false);
    44.             }
    45.         }
    46.         else
    47.         {
    48.             base.Execute(requestContext);
    49.         }
    50.     }
    51. }

  10. Add the following Views to the Views folder (none of them should use a master page):
    • Ping.aspx
    • GetRunParameters.aspx
    • ReportTestResults.aspx
    • SaveLogFile.aspx
  11. Then replace contents of each of these views except GetRunParameters.aspx.

    Code Snippet
    1. <%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %><rsp stat="ok"/>

  12. Add the following content to GetRunParameters.aspx which tells the Silverlight Test Run the name of the computer that is running the tests.
  13. Code Snippet
    1. <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><rsp stat="ok">
    2. <option name="ComputerName" value="<%= Environment.MachineName %>" />
    3. </rsp>

 

That’s it! Now your Silverlight Test Results will be output the the \App_Data\TestResults.trx file on the web server, the file will be replaced each time you run the tests. If you want to change the filename to something unique each time, change the SaveLogFile function accordingly.

Hope this helps!

About these ads
  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: