I want to test using xunit a function that run a task and throw in a that task
For example :
public void doSomething(){
Task.Run(() =>
{
throw new ArgumentNullException();
});
}
When I want to test this function by doing this :
[Fact]
public void TestIfTheMethodThrow()
{
Assert.Throws<ArgumentNullException>(() => doSomething()); // should return true but return false
}
I want that the Task.Run() finish completely then the assert can be done. anyone have a solution ?
Raising and handling exceptions using TPL (the Tasks library) is slightly different, than the "standard" exception handling.
It is meaningful to evaluate only a completed task, so you need to wait for the completion, even if in this case it is an exception.
Have a look at this MSDN article Exception handling (Task Parallel Library).
You have two different options:
add .Wait() to the Task.Run(...)`
Task.Run(() =>
{
throw new ArgumentNullException();
}).Wait();
or wait while the task is completed while(!task.IsCompleted) {}
var task = Task.Run(() =>
{
throw new ArgumentNullException();
});
while(!task.IsCompleted) {}
The test result should be then as expected - an exception is thrown.
It could be, that before the Wait your test has passed sporadically - don't be irritated - in this case the task execution was faster than the test check - this is a dangerous source of subtle errors.
You can write your method using async and await
Read this for reference Asynchronous programming with async and await
The new method look like this, and the caller will decide if want wait or not, if you call with await it will wait the task complete, otherwise it will continue without wait the task completion
public async Task DoSomethingAsync()
{
if (true)
throw new ArgumentNullException();
await FooAsync();
}
In the test:
[Fact]
public async Task TestIfTheMethodThrow()
{
await Assert.ThrowsAsync<ArgumentNullException>(() => DoSomethingAsync());
}
Related
I am using Task.WhenAll to schedule tasks concurrently (more or less of course) and want to rethrow all exceptions rather than the first one what Task.WhenAll would do.
So I want to perfor a continuation whenever any child task faulted or has been canceled.
That's what NotOnRanToCompletion means, right?
Well this actually works but in case that all Tasks actually have completed,
I get a Task Cancelled exception on the Continuation?
var semaphore = new SemaphoreSlim(10);
var tasks = portList.Select(async port =>
{
try
{
await semaphore.WaitAsync();
await this.AddDeviceAsync(bioprocessDevicesDto, template, port);
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks).ContinueWith(t =>
{
// this will make all inner exceptions available
// never null
throw t.Exception;
}, TaskContinuationOptions.NotOnRanToCompletion).ConfigureAwait(false);
That behavior is by-design and documented.
Note that your code is not awaiting the task returned from WhenAll; it's awaiting the continuation from ContinueWith.
ContinueWith is a low-level method with dangerous default behavior. Use await instead:
var tasks = portList.Select(...);
var allTask = Task.WhenAll(tasks);
try { await allTask; }
catch { throw allTask.Exception; }
When you look at the TaskContinuationOptions for NotOnRanToCompletion, it states:
This option is not valid for multi-task continuations.
I would try changing NotOnRanToCompletion to another option that handles multi-task continuations.
I am throwing an OperationCanceledException from three different Tasks and each having slight differences, as per the code below:
static async Task ThrowCancellationException()
{
throw new OperationCanceledException();
}
static void Main(string[] args)
{
var t1 = new Task(() => throw new OperationCanceledException());
t1.Start();
try { t1.Wait(); } catch { }
Task t2 = new Task(async () => throw new OperationCanceledException());
t2.Start();
try { t2.Wait(); } catch { }
Task t3 = ThrowCancellationException();
Console.WriteLine(t1.Status); // prints Faulted
Console.WriteLine(t2.Status); // prints RanToCompletion
Console.WriteLine(t3.Status); // prints Canceled
}
My question is:
Why the statuses are different for each task?
I could understand that there are differences between the code/lambdas marked with async and the lambda not marked with async but the status is different even between the async lambda and the async method running the same code.
I could understand that there are differences between the code/lambdas marked with async and the lambda not marked with async but the status is different even between the async lambda and the async method running the same code.
This isn't quite true.
If you look carefully at that new Task(async () => throw new OperationCanceledException()), you'll see it's calling the overload new Task(Action action) (there's no overload which takes a Func<Task>). This means that it's equivalent to passing an async void method, not an async Task method.
So:
Task t2 = new Task(async () => throw new OperationCanceledException());
t2.Start();
try { t2.Wait(); } catch { }
This compiles to something like:
private static async void CompilerGeneratedMethod()
{
throw new OperationCanceledException()
}
...
Task t2 = new Task(CompilerGeneratedMethod);
t2.Start();
try { t2.Wait(); } catch { }
This grabs a thread from the ThreadPool, and runs CompilerGeneratedMethod on it. When an exception is throw from inside an async void method, the exception is re-thrown somewhere appropriate (in this case, it's re-thrown on the ThreadPool), but the CompilerGeneratedMethod method itself returns straight away. This causes the Task t2 to complete straight away, which is why its status is RanToCompletion.
So what happened to the exception? It's about to bring down your application! Stick a Console.ReadLine at the end of your Main, and see that the application exits before you have a chance to press enter.
This:
Task t3 = ThrowCancellationException();
is very different. It's not attempting to run anything on the ThreadPool. ThrowCancellationException is run synchronously, and synchronously returns a Task which contains the OperationCanceledException. A Task which contains an OperationCanceledException is treated as Canceled.
If you want to run an async method on the ThreadPool, use Task.Run. This has an overload which takes a Func<Task>, which means that:
Task t2 = Task.Run(async () => throw new OperationCanceledException());
Compiles to something like:
private static async Task CompilerGeneratedMethod()
{
throw new OperationCanceledException();
}
...
Task t2 = Task.Run(CompilerGeneratedMethod);
Here, when CompilerGeneratedMethod is executed on the ThreadPool, it returns a Task containing the OperationCanceledException. The Task machinery then transitions the Task t2 to the Canceled state.
As an aside, avoid new Task, and prefer using Task.Run if you want to explicitly run a method on the ThreadPool. There are lots of methods in the TPL which were introduced before async/await, and are confusing when used with it.
When you create a task using the Task constructor, you can provide a CancellationToken as optional argument. The task will result in a Canceled state only in case of an OperationCanceledException that is associated with this specific CancellationToken. Otherwise the exception will be interpreted as a fault. Here is how you can associate an OperationCanceledException with a CancellationToken:
var cts = new CancellationTokenSource();
var t1 = new Task(() =>
{
cts.Cancel();
throw new OperationCanceledException(cts.Token);
}, cts.Token);
About using the Task constructor with an async delegate as argument, the correct way to do it is by creating a nested Task<Task>:
Task<Task> t2 = new Task<Task>(async () => throw new OperationCanceledException());
t2.Start();
try { t2.Result.Wait(); } catch { }
Console.WriteLine(t2.Result.Status); // prints Canceled
I find myself writing code like this a lot:
try
{
cancellationTokenSource.Cancel();
await task.ConfigureAwait(false); // this is the task that was cancelled
}
catch(OperationCanceledException)
{
// Cancellation expected and requested
}
Given that I requested the cancellation, it is expected and I'd really like the exception to be ignored. This seems like a common case.
Is there a more concise way to do this? Have I missed something about cancellation? It seems like there should be a task.CancellationExpected() method or something.
There is a built-in mechanism, the Task.WhenAny method used with a single argument, but it's not very intuitive.
Creates a task that will complete when any of the supplied tasks have completed.
await Task.WhenAny(task); // await the task ignoring exceptions
if (task.IsCanceled) return; // the task is completed at this point
var result = await task; // can throw if the task IsFaulted
It is not intuitive because the Task.WhenAny is normally used with at least two arguments. Also it is slightly inefficient because the method accepts a params Task<TResult>[] tasks argument, so on every invocation an array is allocated in the heap.
I don't think there is anything built-in, but you could capture your logic in extension methods (one for Task, one for Task<T>):
public static async Task IgnoreWhenCancelled(this Task task)
{
try
{
await task.ConfigureAwait(false);
}
catch (OperationCanceledException)
{
}
}
public static async Task<T> IgnoreWhenCancelled<T>(this Task<T> task)
{
try
{
return await task.ConfigureAwait(false);
}
catch (OperationCanceledException)
{
return default;
}
}
Then you can write your code simpler:
await task.IgnoreWhenCancelled();
or
var result = await task.IgnoreWhenCancelled();
(You might still want to add .ConfigureAwait(false) depending on your synchronization needs.)
I assume whatever task is doing uses CancellationToken.ThrowIfCancellationRequested() to check for cancellation. That throws an exception by design.
So your options are limited. If task is an operation you wrote, you could make it not use ThrowIfCancellationRequested() and instead check IsCancellationRequested and end gracefully when needed. But as you know, the task's status won't be Canceled if you do that.
If it uses code you didn't write, then you don't have a choice. You'll have to catch the exception. You can use extension methods to avoid repeating code (Matt's answer), if you want. But you'll have to catch it somewhere.
The cancellation pattern available in C# in called cooperative cancellation.
This basically means that, in order to cancel any operation, there should be two actors which need to collaborate. One of them is the actor requesting the cancellation and the other is the actor listening to cancellation requests.
In order to implement this pattern you need an instance of CancellationTokenSource, which is an object that you can use in order to get an instance of CancellationToken. The cancellation is requested on the CancellationTokenSource instance and is propagated to the CancellationToken.
The following piece of code shows you this pattern in action and hopefully clarifies your doubt about cancellation:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp2
{
public static class Program
{
public static async Task Main(string[] args)
{
using (var cts = new CancellationTokenSource())
{
CancellationToken token = cts.Token;
// start the asyncronous operation
Task<string> getMessageTask = GetSecretMessage(token);
// request the cancellation of the operation
cts.Cancel();
try
{
string message = await getMessageTask.ConfigureAwait(false);
Console.WriteLine($"Operation completed successfully before cancellation took effect. The message is: {message}");
}
catch (OperationCanceledException)
{
Console.WriteLine("The operation has been canceled");
}
catch (Exception)
{
Console.WriteLine("The operation completed with an error before cancellation took effect");
throw;
}
}
}
static async Task<string> GetSecretMessage(CancellationToken cancellationToken)
{
// simulates asyncronous work. notice that this code is listening for cancellation
// requests
await Task.Delay(500, cancellationToken).ConfigureAwait(false);
return "I'm lost in the universe";
}
}
}
Pay attention to the comment and notice that all the 3 outputs for the program are possible.
There is no way to predict which of them will be the actual program result.
The point is that when you await for the task completion you don't know what actually is going to happen. The operation may succeeds or fails before the cancellation took effect, or maybe the cancellation request can be observed by the operation before it runs to completion or fails for an error. From the calling code point of view, all these outcomes are possible and you have no way to make a guess. You need to handle all cases.
So, basically, your code is correct and you are handling the cancellation the way you should.
This book is an excellent reference to learn these things.
My final solution was to create an extension method as suggested by Matt Johnson-Pint. However, I return a boolean indicating whether the task was canceled as shown in Vasil Oreshenski's answer.
public static async Task<bool> CompletionIsCanceledAsync(this Task task)
{
if (task.IsCanceled) return true;
try
{
await task.ConfigureAwait(false);
return false;
}
catch (OperationCanceledException)
{
return true;
}
}
This method has been fully unit tested. I picked the name to be similar to the WaitForCompletionStatus() method in the ParallelExtensionsExtras sample code and the IsCanceled property.
If you are expecting the task to be cancelled BEFORE the await you should check the state of the cancellation token source.
if (cancellationTokenSource.IsCancellationRequested == false)
{
await task;
}
EDIT: As mentioned in the comments this won't do any good if the task is cancelled while awaited.
EDIT 2: This approach is overkill because it acquires additional resource - in hot path this may have performance hit. (i am using SemaphoreSlim but you can use another sync. primitive with the same success)
This is an extension method over existing task. The extension method will return new task which holds information if the original task was cancelled.
public static async Task<bool> CancellationExpectedAsync(this Task task)
{
using (var ss = new SemaphoreSlim(0, 1))
{
var syncTask = ss.WaitAsync();
task.ContinueWith(_ => ss.Release());
await syncTask;
return task.IsCanceled;
}
}
Here is a simple usage:
var cancelled = await originalTask.CancellationExpectedAsync();
if (cancelled) {
// do something when cancelled
}
else {
// do something with the original task if need
// you can acccess originalTask.Result if you need
}
How it works:
Overall it waits for the original task to complete and returns information if was cancelled. The SemaphoraSlim is usually used to limit the access to some resource(expensive) but in this case i am using it to await until the original task has finished.
Notes:
It does not returns the original task. So if you need something that has been returned from it you should inspect the original task.
I need to unit test a method that looks roughly like this:
public async Task DoStuffAsync()
{
var tasks = { dependency.FooAsync(), dependency.BarAsync() };
await Task.WhenAll(tasks);
}
My first approach (using Moq) was like this:
dependency.Setup(d => d.FooAsync()).Returns(Task.FromResult(default(object)));
dependency.Setup(d => d.BarAsync()).Returns(Task.FromResult(default(object)));
await systemUnderTest.DoStuffAsync();
dependency.Verify(d => d.FooAsync(), Times.Once);
dependency.Verify(d => d.BarAsync(), Times.Once);
But this won't do, since if I change the method to something dumb like this:
public async Task DoStuffAsync()
{
var tasks = { dependency.FooAsync(), dependency.BarAsync() };
await tasks[0];
}
the test won't fail. How do I assert that the tasks were awaited?
EDIT:
I think this solution to this problem could be analogous to mine:
let's say I want to test this method for failure, i.e. one of the tasks throws and I want to assert that the exception is propagated. I need to check that for all the tasks, but there could be a dozen tasks awaited by Task.WhenAll. I'd then have to write a dozen tests, each of them would have a different, single task throw an exception, to make sure that all of them are correctly propagated. And writing a dozen same-y tests doesn't sound like a good thing. If I could just assert that all the tasks are awaited - that would solve my problem, as I can trust the async framework to propagate if an error occurs.
You give very little context (programming is all about context :)).
In you particular case if you want check that DoStuffAsync await all tasks returned by dependencies throw exceptions and await for them
For .NET 4.5.1 create helper method to create task with an exception.
static Task CreateTaskWithException(string exceptionMessage)
{
var taskSource = new TaskCompletionSource<object>();
var exception = new Exception(exceptionMessage);
taskSource.SetException(exception);
return taskSource.Task;
}
If you have multiple dependencies you can test for await - you can simple test all of them at once
dependency.Setup(d => d.FooAsync()).Returns(CreateTaskWithException("Foo"));
dependency.Setup(d => d.BarAsync()).Returns(CreateTaskWithException("Bar"));
dependency.Setup(d => d.FizzBuzzAsync()).Returns(CreateTaskWithException("FizzBuzz"));
var expectedErrors = new[] { "Foo", "Bar", "FizzBuzz" };
string[] actualErrors = null;
try
{
DoStuffAsync().Wait();
Assert.Fail("DoStuffAsync should throw exception");
}
catch(AggregateException exception)
{
actualErrors = exception.InnerExceptions.Select(ex => ex.Message);
}
actualErrors.Should().BeEquivalentTo(expected);
Test will fail if you not awaiting all tasks.
public async Task DoStuffAsync()
{
var tasks = { dependency.FooAsync(), dependency.BarAsync() };
reutrn Task.WhenAll(tasks.Skip(1));
// Test fail with message:
// Expected subject to be a collection with 2 item(s), but {"Bar"}
// contains 1 item(s) less than {"Foo", "Bar"}.
}
I'm trying to get my head around this code:
[TestFixture]
public class ExampleTest
{
[Test]
public void Example()
{
AwaitEmptyTask().Wait();
}
public async Task AwaitEmptyTask()
{
await new Task(() => { });
}
}
The method Example never ends and blocks forever. Why??
The fix (from Stubbing Task returning method in async unit test) is to replace await new Task( () => {}) with return Task.FromResult<object>(null); but again, why is this necessary?
I know there are a bunch of questions similar to this one, but none that I've seen seem to explain why this is happening:
Await method that returns Task - spins forever?: I included the await keyword AFAIK correctly
Stubbing Task returning method in async unit test: Doesn't explain why.
Why will an empty .NET Task not complete if started and waited for from a static constructor?: I'm not running in a static context and as far as I can tell the context is consistent
Async methods return null: also gives the solution, but doesn't explain why
async await return Task: discusses Task.FromResult but not why await new Task(() => {}) doesn't work
You're creating a task and never starting it, so it never finishes.
You should be using Task.Run to create a task that you want to start executing immediately, rather than using the Task constructor.
You need to call Start() on your task.
Otherwise, it will never finish.
Even if you changed it to
await Task.Run(() => { });
it may still never complete. When you hit this line, the program creates a continuation task that will continue when the task completes. The fact that the task is empty is irrelevant. At that point, control flow goes back to
AwaitEmptyTask().Wait();
which waits for the task to complete and blocks the current thread.
When the task does complete, it attempts to continue on the current thread. However, it can't, because the thread is blocked by the call to Wait().
Change the awaited line to
await Task.Run(() => { }).ConfigureAwait(false);
This is a common deadlocking problem. Don't mix Wait() and await. See http://msdn.microsoft.com/en-us/magazine/jj991977.aspx