<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://devlicio.us/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Christopher Bennage : Caliburn, Reflection</title><link>http://devlicio.us/blogs/christopher_bennage/archive/tags/Caliburn/Reflection/default.aspx</link><description>Tags: Caliburn, Reflection</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Improving Asynchronous Tests for Silverlight</title><link>http://devlicio.us/blogs/christopher_bennage/archive/2011/01/17/improving-asynchronous-tests-for-silverlight.aspx</link><pubDate>Mon, 17 Jan 2011 16:29:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:64651</guid><dc:creator>Christopher Bennage</dc:creator><slash:comments>11</slash:comments><description>&lt;p&gt;First a confession, and I know I’ll invoke shame for this one: I have done Very Little Testing with Silverlight. I won’t bore you with reasons or excuses, but I wasn’t up on the state of unit testing in Silverlight until very recently. (In fact, I might&amp;#160; still be missing some chunks.)&lt;/p&gt;  &lt;h3&gt;The Problem&lt;/h3&gt;  &lt;p&gt;Last week, I started writing some tests for &lt;a title="an Open Source (with a commercial option) document database for the .NET/Windows platform" href="http://www.ravendb.net/" target="_blank"&gt;Raven DB&lt;/a&gt;. I won’t call them ‘unit’ tests because they were really ‘integration’ tests. Specifically, I wanted to test the budding Silverlight client for Raven. This mean that my tests had to make calls to the Raven server, wait for the result, then assert something.&lt;/p&gt;  &lt;p&gt;Large portions of the Silverlight client are cross-compiled and I wanted to do the same with the relevant tests. On the .NET side, a demonstrative test looks like this:&lt;/p&gt;  &lt;pre class="c#:nogutter:nocontrols" name="code"&gt;[Fact]
public void Can_insert_async_and_get_sync()
{
    using (var server = GetNewServer(port, path))
    {
        var documentStore = new DocumentStore { Url = &amp;quot;http://localhost:&amp;quot; + port };
        documentStore.Initialize();

        var entity = new Company { Name = &amp;quot;Async Company&amp;quot; };
        using (var session = documentStore.OpenAsyncSession())
        {
            session.Store(entity);
            session.SaveChangesAsync().Wait();
        }

        using (var session = documentStore.OpenSession())
        {
            var company = session.Load&amp;lt;Company&amp;gt;(entity.Id); // the SL client won’t have sync methods!

            Assert.Equal(&amp;quot;Async Company&amp;quot;, company.Name);
        }
    }
}&lt;/pre&gt;

&lt;p&gt;The client is making use of Task from &lt;a title="The System.Threading.Tasks namespace provides types that simplify the work of writing concurrent and asynchronous code." href="http://msdn.microsoft.com/en-us/library/system.threading.tasks.aspx" target="_blank"&gt;System.Threading.Tasks,&lt;/a&gt; and in case you didn’t know, this namespace has been ported to Silverlight as part of the &lt;a title="Visual Studio Async CTP" href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=18712f38-fcd2-4e9f-9028-8373dc5732b2&amp;amp;displaylang=en" target="_blank"&gt;CTP for the new C# 5 async syntax&lt;/a&gt;.The idea here is to make the async code read synchronously. &lt;/p&gt;

&lt;p&gt;Using &lt;a href="http://staxmanade.blogspot.com/2009/02/xunit-light-for-silverlight.html" target="_blank"&gt;XunitLight&lt;/a&gt;, I was able to cross compile a similar test and run it with the &lt;a title="The Microsoft Silverlight Unit Test Framework is a simple, extensible unit testing solution for Silverlight developers." href="http://code.msdn.microsoft.com/silverlightut" target="_blank"&gt;Silverlight Unit Test Framework&lt;/a&gt;. Only, it didn’t work.&lt;/p&gt;

&lt;p&gt;It doesn’t work because the test is running on the UI thread, and the call to Wait() blocks the execution on the current thread while the Task returned from SaveChangesAsync() executes. This task is making use of WebRequest and deep in the bowels of Silverlight some calls are being marshaled back onto the UI thread. Only that thread is being blocked by Wait(), so nothing happens.&lt;/p&gt;

&lt;h3&gt;The Standard Solution&lt;/h3&gt;

&lt;p&gt;The Silverlight Unit Test Framework has some infrastructure for handling this sort of problem. Jeff Wilcox, who built the framework, talks about asynchronous test support in &lt;a title="Asynchronous test support – Silverlight unit test framework and the UI thread" href="http://www.jeff.wilcox.name/2009/03/asynchronous-testing/" target="_blank"&gt;this post&lt;/a&gt;. Using the standard approach, I ended up with this test:&lt;/p&gt;

&lt;pre class="c#:nogutter:nocontrols" name="code"&gt;[Asynchronous]
[TestMethod]
public void Can_insert_async_and_load_async()
{
    var documentStore = new DocumentStore { Url = &amp;quot;http://localhost:&amp;quot; + port };
    documentStore.Initialize();

    var entity = new Company { Name = &amp;quot;Async Company #1&amp;quot; };
    using (var session_for_storing = documentStore.OpenAsyncSession())
    {
        session_for_storing.Store(entity);
        var result = session_for_storing.SaveChangesAsync();
        EnqueueConditional(() =&amp;gt; result.IsCompleted || result.IsFaulted);
    }

    EnqueueCallback(() =&amp;gt;
    {
        using (var session_for_loading = documentStore.OpenAsyncSession())
        {
            var task = session_for_loading.LoadAsync&amp;lt;Company&amp;gt;(entity.Id);
            EnqueueConditional(() =&amp;gt; task.IsCompleted || task.IsFaulted);
            EnqueueCallback(() =&amp;gt; 
            {
                Assert.Equal(entity.Name, task.Result.Name);
                EnqueueTestComplete();
            });
        }
    });
}&lt;/pre&gt;

&lt;p&gt;The Asynchronous attribute tells the framework to use a queuing mechanism to execute the test. Then in your test, you must carefully arrange the code with various enqueue methods. This was actually one of the simpler tests, a couple of them had even more nesting of EnqueueCallback. It was functional, but my heart hurt.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I should also note that the code you see here is a mix of several things. From the Silverlight Unit Test Framework itself we have [Asynchronous] and the enqueue methods. (These methods are provided on a base class SilverlightTest). In addition, [TestMethod] is part of the Visual Studio Team Test (VSTT). In my .NET example above, I was using [Fact] from XUnit. The Silverlight Unit Test Framework includes a default provider for VSTT. Finally, the Assert.Equal call is from XUnit (well, from XunitLight).&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;The Alternative Solution&lt;/h3&gt;

&lt;p&gt;Writing the tests like this was killing me. So I lifted the syntax used in &lt;a title="free WPF and Silverlight from the stone" href="http://www.codeplex.com/caliburn"&gt;Caliburn&lt;/a&gt; for coroutines and I was able to convert the test to this:&lt;/p&gt;

&lt;pre class="c#:nogutter:nocontrols" name="code"&gt;[Asynchronous]
[TestMethod]
public IEnumerable&amp;lt;Task&amp;gt; Can_insert_async_and_load_async()
{
    var documentStore = new DocumentStore { Url = &amp;quot;http://localhost:&amp;quot; + port };
    documentStore.Initialize();

    var entity = new Company {Name = &amp;quot;Async Company #1&amp;quot;};
    using (var session_for_storing = documentStore.OpenAsyncSession(dbname))
    {
        session_for_storing.Store(entity);
        yield return session_for_storing.SaveChangesAsync();
    }

    using (var session_for_loading = documentStore.OpenAsyncSession(dbname))
    {
        var task = session_for_loading.LoadAsync&amp;lt;Company&amp;gt;(entity.Id);
        yield return task;

        Assert.Equal(entity.Name, task.Result.Name);
    }
}&lt;/pre&gt;

&lt;h3&gt;How This Works&lt;/h3&gt;

&lt;p&gt;I’m leveraging the fact that all of the asynchronous work is performed with &lt;a href="http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx" target="_blank"&gt;Task&lt;/a&gt;. In Caliburn, we use &lt;a title="IResult and Coroutines" href="http://caliburnmicro.codeplex.com/wikipage?title=IResult%20and%20Coroutines&amp;amp;referringTitle=Documentation" target="_blank"&gt;IResult&lt;/a&gt; for the same purpose. You’ll note that my test returns an IEnumerable of Task. I took the default implementation of the provider for VSTT, and I found the bit where the test was actually invoked and I changed it to this (note that &lt;em&gt;methodInfo&lt;/em&gt; contains the test method):&lt;/p&gt;

&lt;pre class="c#:nogutter:nocontrols" name="code"&gt;public virtual void Invoke(object instance)
{
    var type = typeof (IEnumerable&amp;lt;&amp;gt;).MakeGenericType(new[] {typeof(Task)});
    if(type.IsAssignableFrom(methodInfo.ReturnType))
    {
        var executor = instance.GetType().GetMethod(&amp;quot;ExecuteTest&amp;quot;);
        executor.Invoke(instance, new[] {methodInfo});
    } else
    {
        methodInfo.Invoke(instance, None); // this is the original implementation
    }
}&lt;/pre&gt;

&lt;p&gt;I check to see if my test method returns an IEnumerable&amp;lt;T&amp;gt; and if it does, I then look for a method named ExecuteTest on my test class and I invoke that passing in my actual test method as a parameter.&lt;/p&gt;

&lt;pre class="c#:nogutter:nocontrols" name="code"&gt;public void ExecuteTest(MethodInfo test)
{
    var tasks = (IEnumerable&amp;lt;Task&amp;gt;)test.Invoke(this, new object[] { });
    IEnumerator&amp;lt;Task&amp;gt; enumerator = tasks.GetEnumerator();
    ExecuteTestStep(enumerator);
}&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Yes, this code is far from bullet proof. It should check to make sure our test class contains an ExecuteTest method (among other things).&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Finally, ExecuteTestStep takes each of the Task instances that are yielded and calls the various enqueue methods from SilverlightTest.&lt;/p&gt;

&lt;pre class="c#:nogutter:nocontrols" name="code"&gt;private void ExecuteTestStep(IEnumerator&amp;lt;Task&amp;gt; enumerator)
{
    bool moveNextSucceeded = false;
    try
    {
        moveNextSucceeded = enumerator.MoveNext();
    }
    catch (Exception ex)
    {
        EnqueueTestComplete();
        return;
    }

    if (moveNextSucceeded)
    {
        try
        {
            Task next = enumerator.Current;
            EnqueueConditional(() =&amp;gt; next.IsCompleted || next.IsFaulted);
            EnqueueCallback(() =&amp;gt; ExecuteTestStep(enumerator));
        }
        catch (Exception ex)
        {
            EnqueueTestComplete();
            return;
        }
    }
    else EnqueueTestComplete();
}&lt;/pre&gt;

&lt;p&gt;If you are familiar with the source from Caliburn Micro, you’ll notice that this is very similar to the logic for executing IResult instances.&lt;/p&gt;

&lt;p&gt;The complete source, along with a few examples tests, is &lt;a title="Raven-Custom-Silverlight-Unit-Test-Provider" href="https://github.com/bennage/Raven-Custom-Silverlight-Unit-Test-Provider" target="_blank"&gt;available on github&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I’ll likely improve it during the next couple of weeks. For example, there’s no real needs for the attributes when the method returns IEnumerable&amp;lt;Task&amp;gt;.&lt;/p&gt;

&lt;p&gt;Feedback is welcome.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=64651" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/christopher_bennage/archive/tags/Reflection/default.aspx">Reflection</category><category domain="http://devlicio.us/blogs/christopher_bennage/archive/tags/TDD/default.aspx">TDD</category><category domain="http://devlicio.us/blogs/christopher_bennage/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/christopher_bennage/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/christopher_bennage/archive/tags/SoYouDontHaveToHurt/default.aspx">SoYouDontHaveToHurt</category></item></channel></rss>