Skip to content

Assert.That is blocking and might lead to deadlock when used with WCF. #3432

@MikiKaufhold

Description

@MikiKaufhold

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions