Faking WCF Async Calls – Part II

In the last post, I simulated an asynchronous call to WCF, by setting custom code behavior on the Begin and End. But that’s not enough. I want to make that even shorter and readable. And even ready for more generic use.

I’m taking advantage of the fact that for a specific synchronous call in WCF, the generated async proxies have a constant signature. I want to write this in my test code:

myHandle= WCFAsyncWrapper.AsyncCallOf(() => fakeSourceListProvider.GetSourceList(null))
  .WillReturn("Fake Result", 500);

This is a wrapper method, that does what I did before, only reads better, and takes as a parameter the synchronous version of the method, and its WillReturn clause takes two arguments: The fake result I want to return from the server, and the timeout I want to simulate.

True magic indeed. Let’s start. Here’s the WCFAsyncWrapper class:

public class WCFAsyncWrapper
{
   public static IAsyncReturnValueHandler<T> AsyncCallOf<T>(Expression<Func<T>> syncFunction)
  {
      return new AsyncReturnValueHandler<T>(syncFunction);
  }
}

Brilliant, I know. Note that the parameter received is an Expression, not a delegate (as is the default in Isolator APIs). There’s a reason for that – I want to parse the expression for setting behavior on it.

Let’s continue. The AsyncReturnValueHandler class does all the work. Its constructor does the Expression parsing:

public AsyncReturnValueHandler(Expression<Func<T>> syncFunction)
{
  // Parse the expression
  string name = ((MethodCallExpression) syncFunction.Body).Method.Name;
  beginName = "Begin" + name;
  endName = "End" + name;
  instance = GetInstanceFromExpressionTree(syncFunction);
}

The GetInstanceFromExpression method is interesting: It extracts the instance on which the method is invoked. It’s a real reference to the object:

private static object GetInstanceFromExpressionTree<T>(Expression<Func<T>> function)
{
 var method = function.Body as MethodCallExpression;
 var source = method.Object as MemberExpression;
 var constant = source.Expression as ConstantExpression;
 return (source.Member as System.Reflection.FieldInfo).GetValue(constant.Value);
}

A bit of reflection magic. Let’s continue. Now, let’s look at what we return:

public IAsyncResult WillReturn(T value, int afterTime)
{
  returnValue = value;
  timeout = afterTime;

  SetBehavior();
  return returnedHandle;
}

Looks harmless enough. And obviously, SetBehavior is where we set the behavior, similar as before. But this time, I’m using the NonPublic API, which allow me to work with strings as method names. Which is convenient, because I just parsed the synchronous method from the expression, and got me 2 method names for Begin and End. I’m using them with DoInstead and WillReturn respectively.

private void SetBehavior()
{
  Isolate.NonPublic.WhenCalled(instance, beginName)
      .DoInstead((Func<MethodCallContext,object>)( (c) =>
                            {
                                WCFAsynchTests.AsyncProcessor dr = d =>
                                           {
                                               Thread.Sleep(timeout);
                                               d.DynamicInvoke(returnedHandle);
                                           };
                                returnedHandle = dr.BeginInvoke(c.Parameters[1] as Delegate,null, c.Instance);
                                return returnedHandle;

                            }));
  Isolate.NonPublic.WhenCalled(instance, endName).WillReturn(returnValue);
}

That’s enough to pass my test, which looks like this:

[Isolated]
[TestMethod]
public void WaitingOnFakeAsyncOperation_ToComplete()
{
  myHandle= WCFAsyncWrapper.AsyncCallOf(() => fakeSourceListProvider.GetSourceList(null))
      .WillReturn("Fake Result", 500);

  DataProviderClient client = new DataProviderClient();
  myHandle = client.GetSourceListFromServerAsync("<xml></xml>");

  while (!myHandle.IsCompleted)
  {
      Console.WriteLine("Waiting...");
      Thread.Sleep(100);
  }
  Assert.AreEqual("Fake Result", client.SourceList);
}

Let’s look back and see what we did:

    1. Built a wrapper that takes the sync method signature, the expected return value and the expected timeout
    2. Parsed the expression for later use with the NonPublic WhenCalled.
    3. Set the behavior for the Begin and End method
    4. Continue with the Act and Assert part of the test.

 

You can download the sources for this example from here.

PS: Is that cool or is that COOL?

Want to start unit testing? Take advantage of our 15-day FREE trial of Isolator Complete. Get it now

TOP