-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Check.ThatCode for Task-returning methods does not await result in 3.0.0 #339
Comments
thanks for reporting this |
oh oh |
Thanks - let me know if you have any further detail on the regressions - will be helpful to decide if I should hold off upgrading at this point or not. |
nah, there is not much regression. Got fooled by async void method. The problem is that one cannot wait for async void method, no matter how hard you try. And the magic of return type determination for lambda. |
Long story short, I may have to reintroduce Check.ThatAsyncCode |
By the way, actually, you should write your tests this way
Method groups are a forgotten feature, but clean for this kind of code. |
Sure, though it was just an example - in practice the lambda might have a bit more going on in it. Plus I have got into the habit of avoiding method groups since they always incur a method allocation ( before C# 11 - dotnet/roslyn#5835) - we even have a code inspection that reminds us to avoid this. |
And to be clear, I think |
For my own part, I feel it is ok, even good, to accept different standards between tests and production code, but that is not the point here. I was merely pointing out an alternative workaround.
Not sure what you mean here, just be clear , I have tested my proposal and it works.
Not exactly this, but this is part of the problem Explanation follows |
Yep, I am still into this. I may have a way to keep signatures this way, but you are right, it definitely makes more sense to assume Task returning methods are |
To clarify, neither of these pass for me, despite PleaseThrowAsync3 being a trivial pass-through wrapper around PleaseThrowAsync2:
That is, the workaround of using the method group only works if the original method itself has an async state machine implementation, which may not be the case generally for your methods with awaitable return types (which I've remembered is more complex than just matching on |
Thanks for the clarification.
using your examples, it means 1,2,3,4 and 6 will await and pass. 5 will not. What do you think? |
I don't understand the second bullet which is maybe driving you to an API in which 5 will not pass? Are you considering example 5 to be one that is "not explicitly awaitable"? In both of cases 5 and 6, this current resolves to the same method, Is there some confusion here over what is considered to be 'awaitable' ? Awaitable != async. We unfortunately often say "async method" as a shorthand for a method that returns something that can be
The first two are not awaitable, and it does not seem meaningful for Awaitable-ness is the only relevant consideration to the issue at hand (IMO!); whether it has an async implementation is not. To be useful In addition I think the problem is adequately resolved with having a separate |
ClarificationFirst of all, your right about the needed clarification: I kind of mixed async and awaitable, so let me rephrase what I meant. In terms of target API, here is what I have in mind:
Condition for async/awaitable methodsAs said earlier, returning a
CoverageObviously, handling only Task returning method is an acceptable restriction, as one can convert alternative form as you pointed out. I still think IAsyncEnumerable deserves enumeration related API. Origins of
|
Firstly - I don't know enough about On tasks that are not scheduled - is this based on Task.Status? Task statuses change -- maybe it's just not scheduled yet ? Race conditions could result in different behaviour of the assertion, which would be weird. More generally on tasks that will never complete -- I guess my view is that it should be the same as for synchronous code that never completes, e.g. ends up entering an infinite loop or waiting on an event that never gets set - it is the least surprising behaviour if it awaits that completion, even if it never comes. If you try to wait for it in a test without a timeout that seems like a bug in the code or the test. I do think there's an edge case that you may want to test the behaviour of the synchronous portion of an async method, e.g. let's say you have this and you want to test that with invalid input it throws in ValidateInputs in the synchronous portion, without awaiting it:
I guess you could do that with sthg like: Most important thing though is for |
Let me try to answer this, dealing with what I feel is more important first:
|
Released 3.0.1 wit the fix |
Hi - I forgot to say thanks for fixing this so promptly! |
Bug Type
Please pick one:
Describe the bug
I'm upgrading from 2.7.2 to 3.0.0 and have found I had to migrate
.ThatAsyncCode
to.ThatCode
since the former is Obsolete and I treat warnings as errors. https://www.nuget.org/packages/NFluent/3.0.0.351#readme-body-tab advises that this should replace it ("ThatAsyncCode: you can now use ThatCode even for async methods")However, unlike .ThatAsyncCode in the earlier version, .ThatCode does not await the Task for non-generic Task-returning, non-async methods. (However it works fine for
Task<T>
-returning non-async methods, and also for async methods returningTask
).To Reproduce
This throws on the 4th and final
Check.ThatCode
. For now I can explicitly make the lambda async (ie transform code like check 4 to code like check 3), but I don't think this is expected to be required.The equivalent code in 2.7.2 (using
ThatAsyncCode
instead ofThatCode
) does not fail. I encountered this problem when I did a global replace of ThatAsyncCode with ThatCode upon upgrading.I note that
ThatCode<TU>(Func<Task<TU>> awaitableFunc)
callsRunTrace.GetAsyncTrace
, whileThatCode(Func<Task> awaitableFunc)
does not (it callsRunTrace.GetTrace
. which then explicitly checks whether the method is async by inspecting whether it has an AsyncStateMachineAttribute). This explains why it works for check 2 but not check 4. Perhaps the fix is simply to change this method to use GetAsyncTrace?Under the earlier version,
ThatAsyncCode(Func<Task> awaitableMethod)
calledGetAsyncTrace
, which explains why it used to work.Expected behavior
Test code above should not fail, and certainly cases 2 and 4 should not be inconsistent.
Desktop (please complete the following information):
The text was updated successfully, but these errors were encountered: