You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+21-21Lines changed: 21 additions & 21 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,15 +16,15 @@ For example, if we create an `ITimer` with a *due time* and *period* set to **1
16
16
17
17
If we call `Advance(TimeSpan.FromSeconds(1))` three times, effectively moving time forward by three seconds, the timer callback will be invoked once at times `00:01`, `00:02`, and `00:03`, as illustrated in the drawing below. Both `FakeTimeProvider` and `ManualTimeProvider` behaves like this:
18
18
19
-

19
+

20
20
21
21
However, if we instead call `Advance(TimeSpan.FromSeconds(3))` once, the two implementations behave differently. `ManualTimeProvider` will invoke the timer callback at the same time as if we had called `Advance(TimeSpan.FromSeconds(1))` three times, as illustrated in the drawing below:
22
22
23
-

23
+

24
24
25
25
However, `FakeTimeProvider` will invoke the timer callback at time `00:03` three times, as illustrated in the drawings below:
26
26
27
-

27
+

28
28
29
29
Technically, both implementations are correct since the `ITimer` abstractions only promise to invoke the callback timer *on or after the due time/period has elapsed*, never before.
30
30
@@ -33,15 +33,15 @@ However, I strongly prefer the `ManualTimeProvider` approach since it behaves co
33
33
## Known limitations:
34
34
35
35
- If running on .NET versions earlier than .NET 8.0, there is a constraint when invoking `CancellationTokenSource.CancelAfter(TimeSpan)` on the `CancellationTokenSource` object returned by `CreateCancellationTokenSource(TimeSpan delay)`. This action will not terminate the initial timer indicated by the `delay` argument initially passed the `CreateCancellationTokenSource` method. However, this restriction does not apply to .NET 8.0 and later versions.
36
-
- To enable controlling `PeriodicTimer` via `TimeProvider` in versions of .NET earlier than .NET 8.0, the `TimeProvider.CreatePeriodicTimer` returns a `PeriodicTimerWrapper` object instead of a `PeriodicTimer` object. The `PeriodicTimerWrapper` type is just a lightweight wrapper around the original `System.Threading.PeriodicTimer` and will behave identically to it.
36
+
- To enable controlling `PeriodicTimer` via `TimeProvider` in versions of .NET earlier than .NET 8.0, the `TimeProvider.CreatePeriodicTimer` returns a `PeriodicTimerWrapper` object instead of a `PeriodicTimer` object. The `PeriodicTimerWrapper` type is just a lightweight wrapper around the original `System.Threading.PeriodicTimer` and will behave identically to it.
37
37
38
38
## Installation
39
39
40
40
Get the latest release from https://www.nuget.org/packages/TimeProviderExtensions
41
41
42
42
## Set up in production
43
43
44
-
To use in production, pass in `TimeProvider.System` to the types that depend on `TimeProvider`.
44
+
To use in production, pass in `TimeProvider.System` to the types that depend on `TimeProvider`.
45
45
This can be done directly or via an IoC Container, e.g., .NETs built-in `IServiceCollection` like so:
46
46
47
47
```c#
@@ -56,11 +56,11 @@ and in the existing constructor(s) you have, just new up `TimeProvider.System` d
56
56
publicclassMyService
57
57
{
58
58
privatereadonlyTimeProvidertimeProvider;
59
-
59
+
60
60
publicMyService() : this(TimeProvider.System)
61
61
{
62
62
}
63
-
63
+
64
64
publicMyService(TimeProvidertimeProvider)
65
65
{
66
66
this.timeProvider=timeProvider;
@@ -72,15 +72,15 @@ This allows you to explicitly pass in a `ManualTimeProvider` during testing.
72
72
73
73
## Example - control time during tests
74
74
75
-
If a system under test (SUT) uses things like `Task.Delay`, `DateTimeOffset.UtcNow`, `Task.WaitAsync`, or `PeriodicTimer`,
75
+
If a system under test (SUT) uses things like `Task.Delay`, `DateTimeOffset.UtcNow`, `Task.WaitAsync`, or `PeriodicTimer`,
76
76
it becomes hard to create tests that run fast and predictably.
77
77
78
78
The idea is to replace the use of e.g. `Task.Delay` with an abstraction, the `TimeProvider`, that in production
79
79
is represented by the `TimeProvider.System`, which just uses the real `Task.Delay`. During testing it is now possible to
80
80
pass in `ManualTimeProvider`, which allows the test to control the progress of time, making it possible to skip ahead,
81
81
e.g. 10 minutes, and also pause time, leading to fast and predictable tests.
82
82
83
-
As an example, let us test the "Stuff Service" below that performs specific tasks every 10 seconds with an additional
83
+
As an example, let us test the "Stuff Service" below that performs specific tasks every 10 seconds with an additional
84
84
1-second delay. We have two versions, one that uses the standard types in .NET, and one that uses the `TimeProvider`.
0 commit comments