23

I am using Xunit and NMock on .NET platform. I am testing a presentation model where a method is asynchronous. The method creates an async task and executes it so the method returns immediately and the state I need to check aren't ready yet.

I can set a flag upon finish without modifying the SUT but that would mean I would have to keep checking the flag in a while loop for example, with perhaps timeout.

What are my options?

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
Jiho Han
  • 1,610
  • 1
  • 19
  • 41

5 Answers5

48

Just thought you might want an update on this since the #1 answer is actually recommending an older pattern to solve this problem.

In .net 4.5 + xUnit 1.9 or higher you can simply return a Task and optionally use the async keyword from your test to have xunit wait for the test to complete asynchronously.

See this article on xUnit.net 1.9

[Fact]
public async Task MyAsyncUnitTest()
{    
  // ... setup code here ...     
  var result = await CallMyAsyncApi(...);     
  // ... assertions here ...
}
justin.m.chase
  • 13,061
  • 8
  • 52
  • 100
  • Ahh... it's always nice when there is a native support in the framework... Good to know, thanks! – Jiho Han Sep 24 '15 at 14:22
  • 2
    Note that it's important to return a Task and not void: http://stackoverflow.com/questions/23824660/xunit-async-test-not-working-properly – lc. Jun 15 '16 at 06:38
  • 1
    To be more precise the Return Type of the method must be Task, you don't actually need to `return` if you are using async / await. – justin.m.chase Jun 15 '16 at 15:54
20

Does your object feature any sort of signal that the asynchronous method is finished, such as an event? If that is the case, you can use the following approach:

[Test]
public void CanTestAsync()
{
    MyObject instance = new MyObject()
    AutoResetEvent waitHandle = new AutoResetEvent(false); 
    // create and attach event handler for the "Finished" event
    EventHandler eventHandler = delegate(object sender, EventArgs e) 
    {
        waitHandle.Set();  // signal that the finished event was raised
    } 
    instance.AsyncMethodFinished += eventHandler;

    // call the async method
    instance.CallAsyncMethod();

    // Wait until the event handler is invoked
    if (!waitHandle.WaitOne(5000, false))  
    {  
        Assert.Fail("Test timed out.");  
    }  
    instance.AsyncMethodFinished -= eventHandler;    
    Assert.AreEqual("expected", instance.ValueToCheck);
}
Fredrik Mörk
  • 155,851
  • 29
  • 291
  • 343
  • 1
    You should probably close the wait handle when done, as it uses unmanaged resources. I believe these resources will be cleaned up automatically when the handle is collected, but I generally prefer to be explicit when unmanaged resources are used. – Brian Reichle Jan 29 '11 at 08:50
4

My preferred method is to mock out and inject the actual threading mechanism so that under test it is not asynchronous. Some times that is not possible (if the threading of the method is part of the framework, or otherwise not under your control).

If you can't control thread creation, then waiting for the thread to finish in some way, either a while loop or just a timed wait for however long the thread is supposed to take and failing the test if the state is not there since it took too long anyway.

Yishai
  • 90,445
  • 31
  • 189
  • 263
2

check out my article on unit testing Silverlight applications

http://www.codeproject.com/KB/silverlight/Ag3DemoLOB.aspx

There is an example of unit testing a method that calls a WCF service asynchronously...

0

Async Tests with NSubtitute and XUnit are actually pretty straight forward:

 public interface IA
{
    Task<int> DoSomething();
}

called by:

 public class IAmUnderTest
{
    public async Task<int> GetInt(IA a)
    {
        return await a.DoSomething();
    }
}

Because Async methods just return tasks, all you need to do to mock DoSomething() with NSubstitute is use Task.FromResult(). Then the calling code gets a task back that it can still await and get back the integer result.

So mocking it with NSubstitute looks like this:

  public class ATest
{
    [Fact]
    public void DoesSomething()
    {
        var dependency = Substitute.For<IA>();
        dependency.DoSomething().Returns(Task.FromResult(1));

        var target = new IAmUnderTest();
        var id = target.GetInt(dependency).Result;

        id.Should().Be(1);
    }
}

Adding a little extra by making the test async:

  public class ATest
{
    [Fact]
    public async Task DoesSomethingAsync()
    {
        var dependency = Substitute.For<IA>();
        dependency.DoSomething().Returns(Task.FromResult(1));

        var target = new IAmUnderTest();
        var id = await target.GetInt(dependency);

        id.Should().Be(1);
    }
}

The latter is favoured over the former when testing async methods.

Credit to: https://www.garethrepton.com/Unit-Testing-async-methods/#:~:text=Because%20Async%20methods%20just%20return%20tasks%2C%20all%20you,So%20mocking%20it%20with%20NSubstitute%20looks%20like%20this%3A

N Djel Okoye
  • 950
  • 12
  • 10