Rx Reactive extensions: Unit testing with FromAsyncPattern

Posted by Andrew Anderson on Stack Overflow See other posts from Stack Overflow or by Andrew Anderson
Published on 2010-06-10T19:35:41Z Indexed on 2010/06/11 10:22 UTC
Read the original article Hit count: 868

Filed under:
|
|
|
|

The Reactive Extensions have a sexy little hook to simplify calling async methods:

var func = Observable.FromAsyncPattern<InType, OutType>(
  myWcfService.BeginDoStuff,
  myWcfService.EndDoStuff);

func(inData).ObserveOnDispatcher().Subscribe(x => Foo(x));

I am using this in an WPF project, and it works great at runtime.

Unfortunately, when trying to unit test methods that use this technique I am experiencing random failures. ~3 out of every five executions of a test that contain this code fails.

Here is a sample test (implemented using a Rhino/unity auto-mocking container):

[TestMethod()]
public void SomeTest()
{
   // arrange
   var container = GetAutoMockingContainer();

   container.Resolve<IMyWcfServiceClient>()
      .Expect(x => x.BeginDoStuff(null, null, null))
      .IgnoreArguments()
      .Do(
         new Func<Specification, AsyncCallback, object, IAsyncResult>((inData, asyncCallback, state) =>
            {
               return new CompletedAsyncResult(asyncCallback, state);
             }));

   container.Resolve<IRepositoryServiceClient>()
      .Expect(x => x.EndRetrieveAttributeDefinitionsForSorting(null))
      .IgnoreArguments()
      .Do(
         new Func<IAsyncResult, OutData>((ar) =>
         {
            return someMockData;
         }));

   // act
   var target = CreateTestSubject(container);

   target.DoMethodThatInvokesService();

   // Run the dispatcher for everything over background priority
   Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => { }));

   // assert
   Assert.IsTrue(my operation ran as expected);
}

The problem that I see is that the code that I specified to run when the async action completed (in this case, Foo(x)), is never called. I can verify this by setting breakpoints in Foo and observing that they are never reached. Further, I can force a long delay after calling DoMethodThatInvokesService (which kicks off the async call), and the code is still never run. I do know that the lines of code invoking the Rx framework were called.

Other things I've tried:

This improved my failure rate to something like 1 in 5, but they still occurred.

  • I have rewritten the Rx code to use the plain jane Async pattern. This works, however my developer ego really would love to use Rx instead of boring old begin/end.

In the end I do have a work around in hand (i.e. don't use Rx), however I feel that it is not ideal. If anyone has ran into this problem in the past and found a solution, I'd dearly love to hear it.

© Stack Overflow or respective owner

Related posts about c#

Related posts about wpf