3

Let's say we have the following class:

class SampleClass
{
    private readonly IList<int> _numberList = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    public void MethodToBeTested()
    {
        Task.WhenAll(_numberList.Select(async number => { await Task.Run(() => { ProcessNumber(number); }); }));
    }

    private static void ProcessNumber(int number)
    {
        Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId} Number:{number}");
        Thread.Sleep(1000);
    }
}

and we add the following unit test:

[Test]
public void TestMethodToBeTested()
{
    var sampleClass = new SampleClass();
    _sampleClass.MethodToBeTested();
}

The problem is that when the test runs, it doesn't wait for the MethodToBeTested to finish the execution so the output varies. Is there any way to test the full run of this method using NUnit, without changing the method signature (from void to Task) ?

kord
  • 979
  • 14
  • 24
  • 2
    `Task.WhenAll` returns a task object that you have to `await`. The way it is now, it is not doing anything. – Yacoub Massad Jan 28 '16 at 23:41
  • @YacoubMassad: If you run the MethodToBeTested method, in a simple Console application, it will display 10 messages. If you run the same method from the unit test, it varies: it displays three, four, one, depends on how fast the unit test finishes. – kord Jan 28 '16 at 23:52
  • @kord, I think that in your console application you pause execution by using `Console.ReadLine()` or something similar. by doing that you are allowing the tasks run by `MethodToBeTested` to complete. – Yacoub Massad Jan 29 '16 at 00:08
  • @GrantWinney: Right: in this example, the fact that it doesn't throw exception. – kord Jan 29 '16 at 00:08
  • @YacoubMassad: Right: it can be a Console app with Console.ReadLine() at the end, or it can be a windows service that it's continuously running. – kord Jan 29 '16 at 00:20

2 Answers2

1

Using GetAwaiter().GetResult() will make sure that an asynchronous call runs to completion. Read more about that approach vs await here

public void MethodToBeTested()
{
    Task.WhenAll(_numberList.Select(async number => { await Task.Run(() => { ProcessNumber(number); }); })).GetAwaiter().GetResult();
}
Community
  • 1
  • 1
techvice
  • 1,315
  • 1
  • 12
  • 24
0

Just in case someone has tasks that are using the network:

In theory, a unit test shouldn't have network calls, so you don't need to run the tasks. You can fake the calls (Task.FromResult(true)) but if you actually want to make a network call then consider the integration test.