If you've been doing Rx for a while it's very likely you're also be into testing with TDD. In which case you'll have come across testing observable timers but if not then what follows is how easy this is.
So lets say I want to test the following method, it generates a 'tick' according to the time span parameter:
When testing this I don't want to be dependent on the scheduler clock, what I mean is you don't want the test code to have to do some kind of 'wait' operation whilst the Observable.Interval is generating values.
The answer is to use the Reactive Extensions Testing Library. It provides the TestScheduler which allows to manipulate the underlying clock using the AdvanceBy & AdvanceTo methods which then means you can trigger any observable timer in a timely manner!
This means you do have to use the overloaded Observable.Interval to pass the scheduler to the method, I've wrapped the method into a class and I'm using DI to pass in the scheduler:
So now I need a test, I want to simulate generating ticks every minute and I want to receive only 2 ticks:
Which passes as expected...
So lets say I want to test the following method, it generates a 'tick' according to the time span parameter:
1: public IObservable<Unit> TickEvery(TimeSpan timeSpan)
2: {
3: return Observable.Interval(timeSpan).TimeInterval()
4: .Select(_ => new Unit());
5: }
When testing this I don't want to be dependent on the scheduler clock, what I mean is you don't want the test code to have to do some kind of 'wait' operation whilst the Observable.Interval is generating values.
The answer is to use the Reactive Extensions Testing Library. It provides the TestScheduler which allows to manipulate the underlying clock using the AdvanceBy & AdvanceTo methods which then means you can trigger any observable timer in a timely manner!
This means you do have to use the overloaded Observable.Interval to pass the scheduler to the method, I've wrapped the method into a class and I'm using DI to pass in the scheduler:
1: public class MyTicker
2: {
3: private readonly IScheduler _scheduler;
4:
5: public MyTicker(IScheduler scheduler)
6: {
7: _scheduler = scheduler;
8: }
9:
10: public IObservable<Unit> TickEvery(TimeSpan timeSpan)
11: {
12: return Observable.Interval(timeSpan, _scheduler).TimeInterval()
13: .Select(_ => new Unit());
14: }
15: }
So now I need a test, I want to simulate generating ticks every minute and I want to receive only 2 ticks:
1: [TestFixture]
2: public class MyTickerTests
3: {
4: private long _minuteInTicks;
5: private TestScheduler _scheduler;
6:
7: [SetUp]
8: public void SetUp()
9: {
10: // a minute in ticks...
11: _minuteInTicks = new TimeSpan(0, 0, 1, 0).Ticks;
12:
13: // this is the important bit...
14: _scheduler = new TestScheduler();
15: }
16:
17: [Test]
18: public void should_tick_twice_in_three_minutes()
19: {
20: // ARRANGE
21: var ticker = new MyTicker(_scheduler);
22: var tickInternval = TimeSpan.FromMinutes(1);
23: var count = 0;
24:
25: // ACT
26: using (ticker.TickEvery(tickInternval)
27: .Subscribe(_ => count++))
28: {
29: _scheduler.AdvanceBy(_minuteInTicks);
30: _scheduler.AdvanceBy(_minuteInTicks);
31: }
32:
33: _scheduler.AdvanceBy(_minuteInTicks);
34:
35: // ASSERT
36: Assert.AreEqual(count, 2, "the count should have only been incremented twice...");
37: }
38: }
Which passes as expected...
Comments
Post a Comment