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
Add Should().NotThrowAfter assertion for actions #942
Conversation
This extends the NotThrow Action assertion by an overload which allows to specify a wait time. This asserts that the Action should stop throwing exceptions after the wait time has passed.
The overload of NotThrow with waiting time is renamed to NotThrowAfter to emphasize its purpose.
/// Zero or more objects to format using the placeholders in <see cref="because" />. | ||
/// </param> | ||
/// <exception cref="ArgumentOutOfRangeException">Throws if waitTime or pollInterval are negative.</exception> | ||
public void NotThrowAfter(int waitTime, int pollInterval, string because = "", params object[] becauseArgs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔧 I would prefer to use TimeSpan
for waitTime
and pollInterval
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔧 Maybe NotThrowAnymoreAfter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 Do we also need to be able to specify an exception type here?
🤔 Do we also need this assertion for Func<Task>
for consistency with the other exception APIs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe
NotThrowAnymoreAfter
Are you sure? I think that this would be a tad too long. It might also be misleading. Doesn't "anymore" suggest that the Action must have been throwing exceptions at some point
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to use
TimeSpan
forwaitTime
andpollInterval
.
Sounds good. Would you keep an overload with the current signature or would you expect the user to convert from that representation to the TimeSpan?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True. Very true. Alright. Let's stick with NotThrowAfter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you keep an overload with the current signature or would you expect the user to convert from that representation to the TimeSpan?
They can use the TimeSpan
extension methods like 12.Seconds()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we also need to be able to specify an exception type here?
I have not encountered a use case for this so far. This would mean that the Action could be still throwing exceptions but not the specified one ... :confused. We could add it for consistency's sake. You could also wait until someone requests it. I don't know your policy regarding these kind of questions 😏
Do we also need this assertion for
Func<Task>
for consistency with the other exception APIs?
Probably.
/// Zero or more objects to format using the placeholders in <see cref="because" />. | ||
/// </param> | ||
/// <exception cref="ArgumentOutOfRangeException">Throws if waitTime or pollInterval are negative.</exception> | ||
public void NotThrowAfter(int waitTime, int pollInterval, string because = "", params object[] becauseArgs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔧 Maybe NotThrowAnymoreAfter
/// Zero or more objects to format using the placeholders in <see cref="because" />. | ||
/// </param> | ||
/// <exception cref="ArgumentOutOfRangeException">Throws if waitTime or pollInterval are negative.</exception> | ||
public void NotThrowAfter(int waitTime, int pollInterval, string because = "", params object[] becauseArgs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 Do we also need to be able to specify an exception type here?
🤔 Do we also need this assertion for Func<Task>
for consistency with the other exception APIs?
* Change waitTime and pollInterval to TimeSpan * Use Thread.Sleep instead of Task.Delay * Add better exception messages if waitTime or pollInterval are out of range * Add tests for invalid argument exceptions * Simplify tests
The failing build should have been fixed with #944 . |
* Change local variable names to start with a lower case letter in tests of the NotThrowAfter assertion * Change exception message if NotThrowAfter
The build fails as |
The implementation of NotThrowAfter uses Thread.Sleep. This is not supported in older .net standard versions. Hence, Thread.Sleep is replaced by a ManualResetEvent which also allows to wait for a specified time.
@jnyrup Did you have a chance to take a look at my attempt to solve this? |
@frederik-h Sorry for the delayed response. What about if we used something similar to https://github.com/fluentassertions/fluentassertions/blob/master/Src/FluentAssertions/Specialized/ExecutionTimeAssertions.cs and wrap the synchronous function inside a |
Yes, I also hesitated at first, but since the waiting is part of the specified behavior of the method and not some implementation specific side effect, I decided that there is no substantial reason not to use it.
I am not sure that this is a benefit, but I don't have a strong opinion on this matter. This would implement a different functionality than what I was trying to implement, but it could probably be used for more or less the same purpose. What would you do if the Task is not done after the |
@dennisdoomen do you have an opinion on the usage of |
He's not doing concurrent calls, is he? So a simple Thread.Sleep would suffice. |
@dennisdoomen |
So maybe we should not support this method except for .NET Standard 2.0 and higher, and the full .NET Framework. |
Sounds like the best option. |
Test "NotThrowAfter_when_subject_is_async_it_should_not_throw" asserts that NotThrowAfter should throw and hence it is renamed accordingly.
The messages of the exceptions that are raised if the TimeSpan parameters of NotThrowAfter are negative claim that the parameters should be "positive". Changed to "non-negative". Further change: * Minor formatting change
This reverts commit b46d678. NotThrowAfter has to block the current thread. Since Thread.Sleep() is not available on older versions of netstandard, the previous commit introduced a workaround. It seems prefarable not to use this workaround and disable NotThrowAfter for target frameworks that don't support Thread.Sleep().
Older versions of netstandard don't support Thread.Sleep() which is required by NotThrowAfter.
6bafda9
to
fe90171
Compare
Merge latest changes from upstream
I have now implemented this. |
I don't think that my changes have caused the test failure in the test from |
No, that one is unstable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only minor comments. Feel free to reject them.
* Add braces to if * Invert #if condition
Add braces to single line ifs.
For a consistent API, we should probably also expose |
I think we need to be a bit more critical. |
Regarding the |
Would you be willing to pick up the suggestions from @jnyrup? Then we would have a single PR that adds this new API in a consistent API. |
For consistency with the ActionAssertions. Mirrors the implementation for Actions.
c972cf7
to
f22fcdb
Compare
@jnyrup aren't your comments already addressed? |
This should make sure that exceptions will reference the correct part of the code.
@frederik-h regarding the two failing tests, you might want to relax the time limits. |
Regarding the documentation, a description of and just add an example to the block of async examples. |
This should help to avoid test failure on slow systems
Remove async/await which are not necessary here
The wait times of two tests were too low. This caused the tests to fail on a slow system.
Fixup whitespace
So? Is this one ready to be merged? |
Should |
Previously, the return type of NotThrowAfter for Func<T> was void. Now we return the result of the executed func to allow for further assertions on that result.
//----------------------------------------------------------------------------------------------------------- | ||
// Assert | ||
//----------------------------------------------------------------------------------------------------------- | ||
act.Subject.Should().Be(42); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to double check.
Could this be written as
throwShorterThanWaitTime.Should().NotThrowAfter(waitTime, pollInterval)
.Which.Should().Be(42);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes!
@frederik-h Thanks for implementing this feature and contributing to Fluent Assertions. |
@dennisdoomen Push the button. |
Thank you for the constructive review! |
This adds a
Should().NotThrowAfter
assertion for Actions which is a variant ofShould().NotThrow
which asserts that the Action should stop throwing exceptions after a given wait time. See issue #940 for a discussion of this feature.
If this gets merged, it should probably also be considered to add corresponding methods for the other action assertions such as
ThrowAfter
etc.IMPORTANT
master
branch.