Once upon a time, I wrote about writing tests for WCF servers and clients. WCF can be invoked also in an async method. What you would do is generate WCF proxies that have method definition for your service starting with “Begin…” and “End…”, following the asynchronous method calling convention.
As you may recall from our last session, eons ago, my server looks like this:
1 |
[ServiceContract(Namespace = <span class="str">"http://DoesntExist"</span>)]<br /><span class="kwrd">public</span> <span class="kwrd">interface</span> ISourceListProvider<br />{<br /> [OperationContract]<br /> <span class="kwrd">string</span> GetSourceList(<span class="kwrd">string</span> source);<br /><br />} |
And my calling and invoking methods look like this:
1 |
<span class="kwrd">public</span> IAsyncResult GetSourceListFromServerAsync(<span class="kwrd">string</span> source)<br />{<br /> <span class="kwrd">return</span> channel.BeginGetSourceList(source, GetSourceListCallBack, channel);<br />}<br /><br /><span class="kwrd">public</span> <span class="kwrd">void</span> GetSourceListCallBack(IAsyncResult ar)<br />{<br /> sourceList = ((ISourceListProvider) ar.AsyncState).EndGetSourceList(ar);<br /> |
1 |
Console.WriteLine(sourceList);<br />}<br /><br /><span class="kwrd">public</span> <span class="kwrd">string</span> SourceList<br />{<br /> get<br /> {<br /> <span class="kwrd">return</span> sourceList;<br /> }<br />} |
The sourceList attribute gets updated at the end of the operation.
What I want to do is short-circuit the async call. Let’s imagine that the async call takes 1 second from starting, until End gets called. Instead of calling the method asynchronously, I want to wait 1 second, and then call the End method. In fact, I’m testing the client, and faking the server, but keeping the delay.
Here’s my test (there’s a small setup code in the TestInitialize that appear :
1 |
<span class="lnum"> 1: </span><span class="kwrd">private</span> IAsyncResult returnedHandle; |
1 |
<span class="lnum"> 2: </span><span class="kwrd">public</span> <span class="kwrd">delegate</span> <span class="kwrd">void</span> AsyncProcessor(Delegate d); |
1 |
<span class="lnum"> 3: </span> |
1 |
<span class="lnum"> 4: </span>[Isolated] |
1 |
<span class="lnum"> 5: </span>[TestMethod] |
1 |
<span class="lnum"> 6: </span><span class="kwrd">public</span> <span class="kwrd">void</span> AsyncGetSourceList_SimulatedAsync_WithFakeResult() |
1 |
<span class="lnum"> 7: </span>{ |
1 |
<span class="lnum"> 8: </span> Isolate.WhenCalled(()=>fakeSourceListProvider.BeginGetSourceList(<span class="kwrd">null</span>, <span class="kwrd">null</span>, <span class="kwrd">null</span>)) |
1 |
<span class="lnum"> 9: </span> .DoInstead(c=> |
1 |
<span class="lnum"> 10: </span> { |
1 |
<span class="lnum"> 11: </span> AsyncProcessor dr = d=> |
1 |
<span class="lnum"> 12: </span> { |
1 |
<span class="lnum"> 13: </span> Thread.Sleep(1000); |
1 |
<span class="lnum"> 14: </span> d.DynamicInvoke(returnedHandle); |
1 |
<span class="lnum"> 15: </span> }; |
1 |
<span class="lnum"> 16: </span> returnedHandle = dr.BeginInvoke(c.Parameters[1] <span class="kwrd">as</span> Delegate, <span class="kwrd">null</span>, c.Instance); |
1 |
<span class="lnum"> 17: </span> <span class="kwrd">return</span> returnedHandle; |
1 |
<span class="lnum"> 18: </span> |
1 |
<span class="lnum"> 19: </span> }); |
1 |
<span class="lnum"> 20: </span> Isolate.WhenCalled(()=>fakeSourceListProvider.EndGetSourceList(<span class="kwrd">null</span>)).WillReturn(<span class="str">"Fake Result"</span>); |
1 |
<span class="lnum"> 21: </span> DataProviderClient providerClient = <span class="kwrd">new</span> DataProviderClient(); |
1 |
<span class="lnum"> 22: </span> IAsyncResult myHandle = providerClient.GetSourceListFromServerAsync(<span class="str">""</span>); |
1 |
<span class="lnum"> 23: </span> |
1 |
<span class="lnum"> 24: </span> <span class="kwrd">while</span> (!myHandle.IsCompleted) |
1 |
<span class="lnum"> 25: </span> { |
1 |
<span class="lnum"> 26: </span> Console.WriteLine(<span class="str">"Waiting..."</span>); |
1 |
<span class="lnum"> 27: </span> Thread.Sleep(100); |
1 |
<span class="lnum"> 28: </span> } |
1 |
<span class="lnum"> 29: </span> Assert.AreEqual(<span class="str">"Fake Result"</span>, providerClient.SourceList); |
1 |
<span class="lnum"> 30: </span> |
1 |
<span class="lnum"> 31: </span> |
1 |
<span class="lnum"> 32: </span>} |
In lines 8-19, I use the new and ingenious DoInstead on the Begin method. It lets me define the custom code that will be executed when the Begin method gets called. In our case, the custom code is calling our delegate asynchronously. On the other thread, the delegate includes sleeping for the timeout, and then calling the End method.
In line 20 I set the return value I want to simulate coming from the server. That’s all I need to do!
I used the Console.WriteLine calls to show what happens when I wait for the method to return. When I run it, here’s what happens:
This is pretty cool by itself. But wait, there’s more! In my next post, I’m going to do a bit more magic.