开发者

Unit test for asynchronous delegate call in c#

开发者 https://www.devze.com 2023-03-31 20:31 出处:网络
I have a function which created a delegated and starts BeginInvoke on that object, with another function being passed in to wait for EndInvoke:

I have a function which created a delegated and starts BeginInvoke on that object, with another function being passed in to wait for EndInvoke:

    private static void DeploymentComponentThreadedCallBack(IAsyncResult ar)
    {
        var result = (AsyncResult)ar;
        var pluginExecuteAction = (Action<int, Guid, int, EnvironmentServerComponentSet, string>)result.AsyncDelegate;
        pluginExecuteAction.EndInvoke(ar);
        //report back to WCF service that thread is finished
    }

public void DeployComponent(byte[] resource, Guid componentGuid, string deploymentType, Dictionary<string, object> args)
{
  var asyncCallback = new AsyncCallback(DeploymentComponentThreadedCallBack);
  IDeployComponent plugin = GetPluginDelegate();
  Action<byte[], Guid, string, Dictionary<string, object>> pluginExecuteAction = plugin.DeployComponent;
  IAsyncResult ar = pluginExecuteAction.BeginInvoke(resource, componentGuid, deploymentType, args, asyncCallback, null);
}

I'd like to unit test this, but when I do so, DeploymentComponentThreade开发者_C百科dCallBack never gets hit, and obviously neither does the EndInvoke call. I presume this is happening because the test passes before the asynchronous thread ends, so the thread stops executing before EndInvoke, but is there a way I can stop this happening so I can see that EndInvoke gets hit?

Cheers, Matt


I think your basic problem is that you're not exposing anything on the DeployComponent method that would let you track the asynchronous operation that you're starting there. If you returned the IAsyncResult from there you could call ar.AsyncWaitHandle.WaitOne() to wait until it completed.


As far as I remember the AsyncResult has a flag (IsCompleted) that tells you whether the operation is going on. Wait on it (e.g. primitively with a while loop), and then do your assertions


You simply need to make an injection point to turn asynchrounous calls into blocking calls. For example:

 public class MethodInvoker
 {
     public virtual void Invoke(Action begin, Action<IAsyncResult> end)
     {
          begin.BeginInvoke(end, null);
     }
 }

With a unit testing version like so:

 public class SynchronousInvoker : MethodInvoker
 {
     public override void Invoke(Action begin, Action<IAsyncResult> end)
     {
         begin();
         end();
     }
 }

Then you would write code like so:

 _myMethodInvoker.Invoke(pluginExecuteAction, asyncCallback);

Which in the context of your normal functionality, is asynchronous. In your unit tests, you simply inject the SynchronousInvoker in it's place and it becomes a blocking call.

0

精彩评论

暂无评论...
验证码 换一张
取 消