Testing Time and Concurrency with Rx - TestCon...

51
1 Tamir Dresher (@tamir_dresher) Senior Software Architect J Testing Time and Concurrency with Rx 1

Transcript of Testing Time and Concurrency with Rx - TestCon...

Page 1: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

1

Tamir Dresher (@tamir_dresher)

Senior Software ArchitectJ

Testing Time and Concurrency with Rx

1

Page 2: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

2

• Author of Rx.NET in Action (manning publications)

• Software architect, consultant and instructor

• Software Engineering Lecturer @ Ruppin Academic Center

• OzCode (www.oz-code.com) Evangelist

@[email protected]://www.TamirDresher.com.

About Me

Page 3: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Reactive Extensions (Rx)

Your headache relief pill to Asynchronous Event

based applications

AsyncPush

Triggers

Events

3

Page 4: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Reacting to changes

4

Page 5: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

IEnumerable<Message> LoadMessages(string hashtag)

{

var statuses = facebook.Search(hashtag);

var tweets = twitter.Search(hashtag);

var updates = linkedin.Search(hashtag);

return statuses.Concat(tweets).Concat(updates);

}

Twitter App

Linkedin

Facebook

Pull ModelPull Model

5

Page 6: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

???? LoadMessages(string hashtag)

{

facebook.Search(hashtag);

twitter.Search(hashtag);

linkedin.Search(hashtag);

}

DoSomething( )msg

Push ModelPush Model

6

Page 7: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

namespace System{

public interface IObservable<out T>{

IDisposable Subscribe(IObserver<T> observer);}

public interface IObserver<in T>{

void OnNext(T value);void OnError(Exception error);void OnCompleted();

}}

InterfacesInterfaces

7

Page 8: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

observable observer

Subscribe(observer)

subscription

OnNext(X1)

OnNext(Xn)⁞

IDisposable

Observables and ObserversObservables and Observers

8

Page 9: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

OnCompleted()

OnError(Exception)

observable observer

Observables and ObserversObservables and Observers

9

Page 10: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Rx packages

10

Page 11: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Push ModelPush Model with Rx Observables

class ReactiveSocialNetworksManager{

//members

public IObservable<Message> ObserveMessages(string hashtag){

:}

}

var mgr = new ReactiveSocialNetworksManager();

mgr.ObserveMessages("Rx").Subscribe(

msg => Console.WriteLine($"Observed:{msg} \t"),ex => { /*OnError*/ },() => { /*OnCompleted*/ });

11

Page 12: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Creating Observables

12

Page 13: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Observable.Range(1, 10)

.Subscribe(x => Console.WriteLine(x));

Observable.Interval(TimeSpan.FromSeconds(1)).Subscribe(x => Console.WriteLine(x));

Observable.FromEventPattern(SearchBox, "TextChanged")

⁞1 sec 1 sec

Observables Factories

Observables Factories

13

Page 14: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Observable Queries (Rx Operators)

14

Page 15: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Filtering Projection Partitioning Joins Grouping Set

Element Generation Quantifiers Aggregation Error HandlingTime and Concurrency

Where

OfType

Select

SelectMany

Materialize

Skip

Take

TakeUntil

CombineLatest

Concat

join

GroupBy

GroupByUntil

Buffer

Distinct

DistinctUntilChanged

Timeout

TimeInterval

ElementAt

First

Single

Range

Repeat

Defer

All

Any

Contains

Sum

Average

Scan

Catch

OnErrorResumeNext

Using

Rx operators

15

Page 16: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Reactive SearchReactive Search

16

Page 17: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

1. At least 3 characters2. Don’t overflow server (0.5 sec delay)3. Don’t send the same string again4. Discard results if another search was requested

Reactive Search - RulesReactive Search - Rules

17

Page 18: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

18

Page 19: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

19

Page 20: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

20

Where(s => s.Length > 2 )

Page 21: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

21

Where(s => s.Length > 2 )

Throttle(TimeSpan.FromSeconds(0.5))

Page 22: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

22

Where(s => s.Length > 2 )

Throttle(TimeSpan.FromSeconds(0.5))

DistinctUntilChanged()

Page 23: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

24

Select(text => SearchAsync(text))

“REA”

“REAC”

Switch()

“REA” results are ignored since we switched to the “REAC” results

Page 24: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Abstracting Time and Concurrency

25

Page 25: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Thread Pool

Task Scheduler

other

SchedulersSchedulers

26

Page 26: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

public interface IScheduler{

DateTimeOffset Now { get; }

IDisposable Schedule<TState>( TState state, Func<IScheduler, TState, IDisposable> action);

IDisposable Schedule<TState>(TimeSpan dueTime, TState state,Func<IScheduler, TState, IDisposable> action);

IDisposable Schedule<TState>(DateTimeOffset dueTime, TState state,Func<IScheduler, TState, IDisposable> action);

}

27

Page 27: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

//// Runs a timer on the default scheduler//IObservable TimeSpan

//// Every operator that introduces concurrency// has an overload with an IScheduler//IObservable T TimeSpan

IScheduler scheduler);

Parameterizing ConcurrencyParameterizing Concurrency

28

Page 28: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

textChanged.Throttle(TimeSpan.FromSeconds(0.5),

DefaultScheduler.Instance).DistinctUntilChanged().SelectMany(text => SearchAsync(text)).Switch().Subscribe(/*handle the results*/);

29

Page 29: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

//// runs the observer callbacks on the specified // scheduler.//IObservable T ObserveOn<T>(IScheduler);

//// runs the observer subscription and unsubsciption on// the specified scheduler.//IObservable T SubscribeOn<T>(IScheduler)

Changing Execution ContextChanging Execution Context

30

Page 30: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

textChanged.Throttle(TimeSpan.FromSeconds(0.5)).DistinctUntilChanged().Select(text => SearchAsync(text)).Switch().ObserveOn(DispatcherScheduler.Current).Subscribe(/*handle the results*/);

Changing Execution ContextChanging Execution Context

31

Page 31: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

textChanged.Throttle(TimeSpan.FromSeconds(0.5)).DistinctUntilChanged().Select(text => SearchAsync(text)).Switch().ObserveOnDispatcher().Subscribe(/*handle the results*/);

Changing Execution ContextChanging Execution Context

32

Page 32: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Virtual Time

What is time?

Time can be a anything that is sequential and comparable

33

“Time is the indefinite continued progress of existence and events ... Time

is a component quantity of various measurements used

to sequence events, to compare the duration of events or the intervals

between them…”

https://en.wikipedia.org/wiki/Time

Page 33: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Virtual Time Scheduler

34

public abstract class VirtualTimeSchedulerBase<TAbsolute, TRelative> : IScheduler,

IServiceProvider, IStopwatchProvider

where TAbsolute : IComparable<TAbsolute>

{

public TAbsolute Clock { get; protected set;}

public void Start()

public void Stop()

public void AdvanceTo(TAbsolute time)

public void AdvanceBy(TRelative time)

...

}

public class TestScheduler : VirtualTimeScheduler<long, long>{

...}

Page 34: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Testing Rx

35

Page 35: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

1. At least 3 characters One letter word, No Search performed

2. Don’t overflow server (0.5 sec delay) 2 words typed, 0.2 sec gap, search only the last

3. Don’t send the same string again 2 words, 1 sec gap, same value, search only first

4. Discard results if another search was requested 2 words, 1 sec gap, slow first search, fast last search, last results shown

Reactive Search - RulesReactive Search – Rules Tests

36

Page 36: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Questions and Answers

Q: How can we test the code without a real user interaction?

Q: How can we test the code without a real server?

Q: How can we test the code deterministically without a real asynchronicity and concurrency?

Q: How can we test the code without REALLY waiting for the time to pass?

37

A: Separation of concerns. Separate the logic from the view

A: Enable Dependency Injection and mock the service client

A: Leverage the Rx Schedulers and provide a Scheduler you can control via DI

A: Leverage the Rx TestScheduler which provides a virtualization of time

Page 37: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Separating the logic from the view

38

SearchView(Presentation, Logic, State)

SearchView(Presentation)

SearchViewModel(Logic, State)

Before

After

Page 38: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Separating the logic from the view

39

<Window x:Class="TestableReactiveSearch.SearchView"><DockPanel>

<TextBox x:Name="SearchBox"Text="{Binding SearchTerm …}"DockPanel.Dock="Top“/>

<ListBox x:Name="SearchResults"ItemsSource="{Binding SearchResults}“/>

</DockPanel></Window>

public class SearchViewModel : INotifyPropertyChanged

{

public event PropertyChangedEventHandler PropertyChanged;

public SearchViewModel()

{

// Rx query

}

public string SearchTerm { get { ... } set { ... } }

public IEnumerable<string> SearchResults { get { ... } set { ... } }}

SearchView.xaml

SearchViewModel.cs

Page 39: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Separating the logic from the view – fixing the Rx query

40

public SearchViewModel()

{

var terms =

Observable.FromEventPattern<PropertyChangedEventArgs>(this, nameof(PropertyChanged))

.Where(e => e.EventArgs.PropertyName == nameof(SearchTerm))

.Select(_ => SearchTerm);

_subscription =

terms

.Where(txt => txt.Length >= 3)

.Throttle(TimeSpan.FromSeconds(0.5))

.DistinctUntilChanged()

.Select(txt => searchServiceClient.SearchAsync(txt))

.Switch()

.ObserveOnDispatcher()

.Subscribe(

results => SearchResults = results,

err => { Debug.WriteLine(err); },

() => { /* OnCompleted */ });

}

Same query as before

Page 40: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Injecting the Search Service client

41

public class SearchViewModel : INotifyPropertyChanged

{

public event PropertyChangedEventHandler PropertyChanged;

public SearchViewModel()

{

// rest of rx query

}

...}

Page 41: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Injecting the Search Service client

42

public class SearchViewModel : INotifyPropertyChanged

{

public event PropertyChangedEventHandler PropertyChanged;

public SearchViewModel(ISearchServiceClient searchServiceClient)

{

// rest of rx query

}

...}

Page 42: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Simple test – first try

43

[TestMethod]

public void Search_OneLetterWord_NoSearchSentToService()

{

var fakeServiceClient = Substitute.For<ISearchServiceClient>();

var vm = new SearchViewModel(fakeServiceClient);

vm.SearchTerm = "A";

fakeServiceClient.DidNotReceive().SearchAsync("A");

}

Page 43: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Injecting concurrency

44

public interface IConcurrencyProvider{

IScheduler TimeBasedOperations { get; }IScheduler Task { get; }IScheduler Thread { get; }IScheduler Dispatcher { get; }

}class ConcurrencyProvider : IConcurrencyProvider{

public ConcurrencyProvider(){

TimeBasedOperations = DefaultScheduler.Instance;Task = TaskPoolScheduler.Default;Thread = NewThreadScheduler.Default;Dispatcher=DispatcherScheduler.Current;

}

public IScheduler TimeBasedOperations { get; }public IScheduler Task { get; }public IScheduler Thread { get; }public IScheduler Dispatcher { get; }

}

Page 44: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Injecting concurrency

45

public SearchViewModel(ISearchServiceClient searchServiceClient,

IConcurrencyProvider concurrencyProvider)

{

var terms =

Observable.FromEventPattern<PropertyChangedEventArgs>(this, nameof(PropertyChanged))

.Where(e => e.EventArgs.PropertyName == nameof(SearchTerm)).Select(_=>SearchTerm);

_subscription =

terms

.Where(txt => txt.Length >= 3)

.Throttle(TimeSpan.FromSeconds(0.5), concurrencyProvider.Thread)

.DistinctUntilChanged()

.Select(txt => searchServiceClient.SearchAsync(txt))

.Switch()

.ObserveOn(concurrencyProvider.Dispatcher)

.Subscribe(

results => SearchResults = results,

err => { Debug.WriteLine(err); },

() => { /* OnCompleted */ });

}

Page 45: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Simplest Rx Test

Install-Package Microsoft.Reactive.Testing

To simplify the Rx testing, derive your test class from ReactiveTest

46

using Microsoft.Reactive.Testing;

[TestClass]

public class SearchViewModelTests : ReactiveTest

{

// Test Methods

}

Page 46: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Test 1: Search is sent after half a sec

47

const long ONE_SECOND = TimeSpan.TicksPerSecond;

[TestMethod]

public void MoreThanThreeLetters_HalfSecondGap_SearchSentToService()

{

var fakeServiceClient = Substitute.For<ISearchServiceClient>();

var fakeConcurrencyProvider = Substitute.For<IConcurrencyProvider>();

var testScheduler = new TestScheduler();

fakeConcurrencyProvider.ReturnsForAll<IScheduler>(testScheduler);

var vm = new SearchViewModel(fakeServiceClient, fakeConcurrencyProvider);

testScheduler.Start();

vm.SearchTerm = "reactive";

testScheduler.AdvanceBy(ONE_SECOND / 2);

fakeServiceClient.Received().SearchAsync("reactive");

}

Page 47: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

TestScheduler

TestScheduler provides two methods for creating observables:CreateColdObservable – Creates an observable that emits its value relatively to when each observer subscribes.

CreateHotObservable – Creates and observable that emits its values regardless to the observer subscription time, and each emission is configured to the absolute scheduler clock

48

var testScheduler = new TestScheduler();

ITestableObservable<int> coldObservable = testScheduler.CreateColdObservable<int>(OnNext<int>(20, 1),OnNext<int>(40, 2),OnCompleted<int>(60)

);

Page 48: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Test 2: first search is discarded if another search happens

49

public void TwoValidWords_SlowSearchThenFastSearch_SecondSearchResultsOnly()

{

var fakeServiceClient = Substitute.For<ISearchServiceClient>();

var fakeConcurrencyProvider = Substitute.For<IConcurrencyProvider>();

var testScheduler = new TestScheduler();

fakeConcurrencyProvider.ReturnsForAll<IScheduler>(testScheduler);

fakeServiceClient.SearchAsync("first").Returns(testScheduler.CreateColdObservable(

OnNext<IEnumerable<string>>(2 * ONE_SECOND, new[] {"first"}), ...);

fakeServiceClient.SearchAsync("second").Returns(testScheduler.CreateColdObservable(

OnNext<IEnumerable<string>>(1, new[] { "second" }), ...);

var vm = new SearchViewModel(fakeServiceClient, fakeConcurrencyProvider);

testScheduler.Start();

vm.SearchTerm = "first";

testScheduler.AdvanceBy(ONE_SECOND);

vm.SearchTerm = "second";

testScheduler.AdvanceBy(5 * ONE_SECOND);

Assert.AreEqual("second", vm.SearchResults.First());

}

Page 49: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Summary

Pull vs. Push model

Rx operators

Building Rx queries

Rx Concurrency Model

Virtual Time

Testing Time and Concurrency with TestScheduler

50

Page 50: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

Your headache relief pill to Asynchronous and

Event based applications

AsyncPush

Triggers

Events

Reactive ExtensionsReactive Extensions

51

Page 51: Testing Time and Concurrency with Rx - TestCon Moscowtestconf.ru/.../2017/...Testing-Time-and-Concurrency-Rx.NET-Schedulers.pdf · 1 Tamir Dresher (@tamir_dresher) Senior Software

www.reactivex.io github.com/Reactive-Extensionswww.manning.com/dresher

Thank You

Tamir Dresher (@tamir_dresher)

52