Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building unit tests for MVC2 AsyncControllers

I'm considering re-rewriting some of my MVC controllers to be async controllers. I have working unit tests for these controllers, but I'm trying to understand how to maintain them in an async controller environment.

For example, currently I have an action like this:

public ContentResult Transaction()
{
    do stuff...
    return Content("result");
}

and my unit test basically looks like:

var result = controller.Transaction();
Assert.AreEqual("result", result.Content);

Ok, that's easy enough.

But when your controller changes to look like this:

public void TransactionAsync()
{
    do stuff...
    AsyncManager.Parameters["result"] = "result";
}

public ContentResult TransactionCompleted(string result)
{
    return Content(result);
}

How do you suppose your unit tests should be built? You can of course invoke the async initiator method in your test method, but how do you get at the return value?

I haven't seen anything about this on Google...

Thanks for any ideas.

like image 224
ChrisW Avatar asked Jun 03 '10 18:06

ChrisW


1 Answers

As with any async code, unit testing needs to be aware of thread signalling. .NET includes a type called AutoResetEvent which can block the test thread until an async operation has been completed:

public class MyAsyncController : Controller
{
  public void TransactionAsync()
  {
    AsyncManager.Parameters["result"] = "result";
  }

  public ContentResult TransactionCompleted(string result)
  {
    return Content(result);
  }
}

[TestFixture]
public class MyAsyncControllerTests
{
  #region Fields
  private AutoResetEvent trigger;
  private MyAsyncController controller;
  #endregion

  #region Tests
  [Test]
  public void TestTransactionAsync()
  {
    controller = new MyAsyncController();
    trigger = new AutoResetEvent(false);

    // When the async manager has finished processing an async operation, trigger our AutoResetEvent to proceed.
    controller.AsyncManager.Finished += (sender, ev) => trigger.Set();

    controller.TransactionAsync();
    trigger.WaitOne()

    // Continue with asserts
  }
  #endregion
}

Hope that helps :)

like image 94
Matthew Abbott Avatar answered Sep 17 '22 14:09

Matthew Abbott