I'm trying to test that my custom IProgress is doing what I expect it to do: "Report" the current status after every second.
So I have some code but it's always failing. But this is the kicker - it's only failing when I have hardly any code in the test case.
If I add in one more piece of code to the test (which is commented out in the repo) .. it works if I uncomment that.
It's like .. something needs to get fired off .. but it hasn't completed before the "assertions" are checked.
Full fiddle: https://dotnetfiddle.net/qXHzlx
Here's the code:
// Arrange.
var reportValue = 0;
var progress = new TimerProgress<int>((int value) => reportValue = value);
await Task.Delay(TimeSpan.FromSeconds(2)); // Need to wait more than 1 second for the report to work.
// Act.
progress.Report(5);
// Assert.
reportValue.ShouldBe(5);
and the custom TimerProgress
:
public class TimerProgress<T> : IProgress<T>
{
private readonly TimeSpan _intervalInMilliseconds;
private readonly IProgress<T> _progress;
private DateTime? _lastReportedOn;
public TimerProgress(Action<T> handler, double intervalInMillieconds = 1000)
{
if (intervalInMillieconds <= 0)
{
throw new ArgumentOutOfRangeException(nameof(intervalInMillieconds));
}
_intervalInMilliseconds = TimeSpan.FromMilliseconds(intervalInMillieconds);
_progress = new Progress<T>(handler);
_lastReportedOn = DateTime.UtcNow;
}
public void Report(T value)
{
var now = DateTime.UtcNow;
if (now - _lastReportedOn > _intervalInMilliseconds)
{
// We're due for a report!
_progress.Report(value);
}
_lastReportedOn = now;
}
}
With the test case, I expect:
- new
TimeProgress
instance.Now
is "remembered". - Wait 2 seconds (you'll see why in a tick)
- "Report". This now checks to see if
remembered-now
is over 1 second ago. It should be because we've waited for 2 seconds! So now, we should "report" - Handler gets called .. which 'remembers' the number 5
- we now assert that '5' was ended up getting reported.
So I keep getting a failure assertion saying the value is 0
, not 5
.
But when I add one more line of code to the test, then the value is now 5
.
Is this about a timing or event firing issue?
Is this about how my handler is trying to update a variable outside of the handler, which is Bad™️ ?
Edit
Suggestions from people are saying that the Progress<T>
actually uses a sync context under the hood and this is the issue?