Unit testing the IAsyncResult pattern

The IAsnycResult pattern is a way of executing asynchronous operations using a BeginOperation and an EndOperation method. You can either use a callback or a wait handle to complete an operation.

Although it is a little less intuitive than the event based pattern that WCF offers by default, it has the advantage that you can run it directly against a service contract of a WCF service. Unit testing the pattern is also on the slightly non-unintuitive side, but not as bad as it looks on first glance.

Let’s unit-test this: we’ve got an asynchronous call of a method on a WCF service that echos a value.

public class EchoViewModel
  {
    // In this example, the service client is passed into the ViewModel via DI
    [Dependency]
    public IEchoService EchoService
    {
      get;
      set;
    }

    private string _toBeEchoed;
    public string ToBeEchoed
    {
      get
      {
        return _toBeEchoed;
      }
      set
      {
        _toBeEchoed = value;
        Echo( _toBeEchoed );
      }
    }

    public string Echoed
    {
      get; set;
    }

    protected void Echo(string value)
    {
      EchoService.BeginEcho( value, EchoComplete, null );
    }

    protected void EchoComplete(IAsyncResult asyncResult)
    {
      Echoed = EchoService.EndEcho( asyncResult );
    }
  }

Now what do we need to cover in a good unit test?

  • The Begin method of the web service is called. This method starts an asynchronous operation. It accepts the parameters that are passed to the web service (and that are defined on the synchronous operation), as well as two extra parameters: The callback method to call when the web service call completes, and an object to transfer arbitrary state to that callback method.
    The test should cover that the method is called with the correct parameters.
  • When the service call completes, the callback method is called. This method has a single parameter: the state of the asynchronous method call; an object that supports the interface IAsyncResult. The test needs to verify that this method is called.
  • The callback method calls into the End method of the web service. This method always has a single parameter: the IAsyncResult that is passed to the callback method. The End method returns the result of the web service call, or throws an exception if the web service call has not succeeded.

To observe these method calls, the service arrangement needs to set up expectations about what it going to happen – enter Rhino.Mocks.

Let’s see what we can do  to arrange a test setup:

    public void ArrangeEchoService(string toBeEchoed, string result)
    {
      // Prepare the result of the asyncronous operation. Since you can't easily
      // instantiate IAsyncResult, use a stub object - you find it in the downloadable
      // code (see end of article).
      IAsyncResult asyncResult = new StubAsyncResult( null );

      // Call Rhino.Mocks to expect BeginEcho is called with the right parameters.
      // Because the callback method is protected, we cannot directly set up a
      // parameter constraint against it; instead, we accept anything as a callback.
      // The correctness of the callback is asserted by actually calling it.
      var expectBeginMethod = _tested.EchoService
         .Expect( x => x.BeginEcho( null, null, null ) )
         .IgnoreParameters()
         .Repeat.Once()
         .Constraints(
           Parameter.Is.Equal( toBeEchoed ),
           Parameter.Is.Anything(),
           Parameter.Is.Null()
        );

      // When the Begin method is called, call the provided callback method.
      // Using the AsyncMethodCall delegate allows providing the code for the Do
      // method as a lambda expression.
      expectBeginMethod
        .Do( new AsyncMethodCall( (param1, callback, state) =>
        {
          callback.Invoke( asyncResult );
          return asyncResult;
        }  ) );

      // Expect the End method of the asynchronous operation to be called.
      // Return the prepared service result.
      _tested.EchoService
        .Expect( x => x.EndEcho( asyncResult ) )
        .Return( result )
        .Repeat.Once();
    }

A test method that uses this arrangement is fairly simple

    [Test]
    public void Value_StandardBehavior_CallsServiceAndSetsEchoedValue()
    {
      // Arrange
      using (_mock.Record())
      {
        ArrangeEchoService( "ToBeEchoed", "Echoed" );
      }
      // Act
      using (_mock.Playback())
      {
        _tested.ToBeEchoed = "ToBeEchoed";
      }

      // Assert
      Assert.That( _tested.Echoed, Is.EqualTo( "Echoed" ) );
    }

Conclusion:
So we’ve got a fairly decent way of testing asynchronous operations using the IAsyncResult pattern, and callbacks. While setting up the operation behavior is quite a bit of effort, writing the tests itself is fairly easy. To streamline the process in a larger process, the Arrangement methods could be code-generated from the method signature (using T4 or alike).

DOWNLOAD EXAMPLE CODE (Visual Studio 2010 project)

Advertisements
About

Christian is a software architect/developer. He lives in Germany, reads a lot, and likes cycling.

Tagged with: , , , ,
Posted in Coding, Testing

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

%d bloggers like this: