nunit-core team mailing list archive
-
nunit-core team
-
Mailing list archive
-
Message #03275
[Bug 1074568] Re: Assert/Assume should support an async method for the ActualValueDelegate
Hi Charlie, I'm afraid we're going to have some problems with this one.
Here's what we want to accomplish:
Assert.That(async () => { return await Task.FromResult(1); },
Is.EqualTo(1));
The signature of our delegate is "delegate object
ActualValueDelegate(void)" but the .NET async feature supports only
methods returning void Task or Task<T>. In fact, if you try to compile
the above you'll get:
<snip>
Cannot convert lambda expression to type 'object' because it is not a delegate type
Cannot convert async lambda expression to delegate type
'NUnit.Framework.Constraints.ActualValueDelegate'. An async lambda
expression may return void, Task or Task<T>, none of which are
convertible to 'NUnit.Framework.Constraints.ActualValueDelegate'.
Since 'NUnit.Framework.TestDelegate' returns void, a return keyword must not be followed by an object expression
</snip>
The second paragraph in the compiler error is what we need to fix, the
issue being that there is no delegate contravariance, which has been
introduced in, IIRC, C# 3 for generic delegates. In other words,
assigning an instance of a delegate returning Task<T> to a delegate type
returning object is not allowed.
So you would assume that introducing an overload for Assert.That as this
one would fix it:
public static void That(Func<object> method, ...)
But it's not the case as you get this error now:
<snip>
Cannot convert async lambda expression to delegate type 'System.Func<object>'. An async lambda expression may return void, Task or Task<T>, none of which are convertible to 'System.Func<object>'.
</snip>
which is quite misleading to the point of being wrong. Look at the
second sentence, it says that void, Task or Task<T> are not convertible
to System.Func<object>, which is indeed the case but not really what we
are doing here. It cannot infer the type of the lambda but complaining
about incompatible return types which don't make any sense. In fact,
keeping the above overload of Assert.That and changing the test code to
this, it'll stop the compiler complaints:
Assert.That(new Func<Task<int>>(async () => { return await ReturnOne();
}), Is.EqualTo(1));
But nonetheless this is not what we want our users to need to write.
Therefore given the constraint of compiling for 2.0 which in turn
prevents us from exposing types which were not in 2.0, like tasks, I
think the only solution would be to add a generic overload, which won't
require any special changes to the test code:
public static void That<T>(Func<T> method, ...)
How does this sound?
--
You received this bug notification because you are a member of NUnit
Developers, which is subscribed to NUnit V2.
https://bugs.launchpad.net/bugs/1074568
Title:
Assert/Assume should support an async method for the
ActualValueDelegate
Status in NUnit Test Framework:
Triaged
Status in NUnitLite Testing Framework:
Triaged
Status in NUnit V2 Test Framework:
Triaged
Bug description:
Just as Assert.Throws can take an async method as it's argument, it
should be possible to use an async method returning a value for
Assert.That and Assume.That.
To manage notifications about this bug go to:
https://bugs.launchpad.net/nunit-3.0/+bug/1074568/+subscriptions
Follow ups
References