Problem 1)
Suppose you are asserting an asynchronous WCF service call - for the sake of simple example just its completion (for complete implementation see NUnitUsingWCFClientDeadlockReproducer.cs.txt)
Assert.That(async () =>
{
await AsyncCall();
return true;
}, Is.True);
In certain cases this lead to deadlock…
Analysis 1)
There is a great article where Alois explains a case of similar WCF deadlock
The problem is that WCF runs asynchronous method completions on the WCF channel dispatcher which seems to be single threaded just like a UI application with a message pump.
…
A sync/async mixture of remoted methods will likely cause deadlocks
Interestingly, our WCF service has only Async methods…
However, Assert.That ends up with a blocking Task.Wait() call and (likely) causes the deadlock.
Solution 1)
To resolve this we have introduced an async variant for Assert.That using DelayedConstraint that looks like this:
public static Task DelayedAsync<T>(Func<Task<T>> actualValueDelegate, IResolveConstraint expression, int delayInMilliseconds)
(for complete implementation see DelayedAsync.cs.txt)
Problem 2) - Considering upgrade of NUnit from 2.6.6 -> 3.11
We are running into the issue generally known as "Catching AssertionException fails tests" #2758 but also mentioned in #2043, #2040, #2007.
Analysis 2)
As suggested in those threads,
using (new NUnit.Framework.Internal.TestExecutionContext.IsolatedContext()) in the most inner DelayedAsync call resolves the issue.
However, since catching AssertionExceptions is not recommended practise and TestExecutionContext is Internal, I am hesitant to adopt this as a final solution.
Instead I would wish for a native awaitable Assert.That that would implement async all the way pattern as recommended by Stephen Cleary.
Looking forward to your feedback and suggestions.
Problem 1)
Suppose you are asserting an asynchronous WCF service call - for the sake of simple example just its completion (for complete implementation see NUnitUsingWCFClientDeadlockReproducer.cs.txt)
In certain cases this lead to deadlock…
Analysis 1)
There is a great article where Alois explains a case of similar WCF deadlock
Interestingly, our WCF service has only Async methods…
However,
Assert.Thatends up with a blockingTask.Wait()call and (likely) causes the deadlock.Solution 1)
To resolve this we have introduced an async variant for
Assert.ThatusingDelayedConstraintthat looks like this:public static Task DelayedAsync<T>(Func<Task<T>> actualValueDelegate, IResolveConstraint expression, int delayInMilliseconds)(for complete implementation see DelayedAsync.cs.txt)
Problem 2) - Considering upgrade of NUnit from 2.6.6 -> 3.11
We are running into the issue generally known as "Catching AssertionException fails tests" #2758 but also mentioned in #2043, #2040, #2007.
Analysis 2)
As suggested in those threads,
using (new NUnit.Framework.Internal.TestExecutionContext.IsolatedContext())in the most inner DelayedAsync call resolves the issue.However, since catching AssertionExceptions is not recommended practise and TestExecutionContext is Internal, I am hesitant to adopt this as a final solution.
Instead I would wish for a native awaitable Assert.That that would implement async all the way pattern as recommended by Stephen Cleary.
Looking forward to your feedback and suggestions.