SlideShare a Scribd company logo
1 of 52
1
Tamir Dresher (@tamir_dresher)
Senior Software Architect
J
Testing Time and Concurrency with Rx
1
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
@tamir_dresher
tamirdr@codevalue.net
http://www.TamirDresher.com.
About Me
Agenda
Rx Introduction
Concurrency Model
Testing Time and Concurrency with Rx
Reactive Extensions (Rx)
Your headache relief pill to Asynchronous Event
based applications
Async
Push
Triggers
Events
4
Reacting to changes
5
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
6
???? LoadMessages(string hashtag)
{
facebook.Search(hashtag);
twitter.Search(hashtag);
linkedin.Search(hashtag);
}
DoSomething( )msg
Push ModelPush Model
7
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
8
observable observer
Subscribe(observer)
subscription
OnNext(X1)
OnNext(Xn)
⁞
⁞
IDisposable
Observables and ObserversObservables and Observers
9
OnCompleted()
OnError(Exception)

observable observer
⁞
Observables and ObserversObservables and Observers
10
Rx packages
11
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*/ });
12
Creating Observables
13
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
14
Observable Queries (Rx Operators)
15
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
16
Reactive SearchReactive Search
17
1. At least 3 characters
2. Don’t overflow server (0.5 sec delay)
3. Don’t send the same string again
4. Discard results if another search was requested
Reactive Search - RulesReactive Search - Rules
18
19
20
21
Where(s => s.Length > 2 )
 
22
Where(s => s.Length > 2 )
 
Throttle(TimeSpan.FromSeconds(0.5))
23
Where(s => s.Length > 2 )
 
Throttle(TimeSpan.FromSeconds(0.5))
DistinctUntilChanged()

25
Select(text => SearchAsync(text))
“REA”
“REAC”
Switch()
“REA” results are ignored since we
switched to the “REAC” results
Abstracting Time and Concurrency
26
Thread Pool
Task Scheduler
other
SchedulersSchedulers
27
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);
}
28
//
// 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
29
textChanged
.Throttle(TimeSpan.FromSeconds(0.5),
DefaultScheduler.Instance)
.DistinctUntilChanged()
.SelectMany(text => SearchAsync(text))
.Switch()
.Subscribe(/*handle the results*/);
30
//
// 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
31
textChanged
.Throttle(TimeSpan.FromSeconds(0.5))
.DistinctUntilChanged()
.Select(text => SearchAsync(text))
.Switch()
.ObserveOn(DispatcherScheduler.Current)
.Subscribe(/*handle the results*/);
Changing Execution ContextChanging Execution Context
32
textChanged
.Throttle(TimeSpan.FromSeconds(0.5))
.DistinctUntilChanged()
.Select(text => SearchAsync(text))
.Switch()
.ObserveOnDispatcher()
.Subscribe(/*handle the results*/);
Changing Execution ContextChanging Execution Context
33
Virtual Time
What is time?
Time can be a anything that is sequential and comparable
34
“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
Virtual Time Scheduler
35
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>
{
...
}
Testing Rx
36
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
37
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?
38
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
Separating the logic from the view
39
SearchView
(Presentation, Logic, State)
SearchView
(Presentation)
SearchViewModel
(Logic, State)
Before
After
Separating the logic from the view
40
<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
Separating the logic from the view – fixing the Rx query
41
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
Injecting the Search Service client
42
public class SearchViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public SearchViewModel()
{
// rest of rx query
}
...
}
Injecting the Search Service client
43
public class SearchViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public SearchViewModel(ISearchServiceClient searchServiceClient)
{
// rest of rx query
}
...
}
Simple test – first try
44
[TestMethod]
public void Search_OneLetterWord_NoSearchSentToService()
{
var fakeServiceClient = Substitute.For<ISearchServiceClient>();
var vm = new SearchViewModel(fakeServiceClient);
vm.SearchTerm = "A";
fakeServiceClient.DidNotReceive().SearchAsync("A");
}
Injecting concurrency
45
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; }
}
Injecting concurrency
46
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 */ });
}
Simplest Rx Test
Install-Package Microsoft.Reactive.Testing
To simplify the Rx testing, derive your test class from ReactiveTest
47
using Microsoft.Reactive.Testing;
[TestClass]
public class SearchViewModelTests : ReactiveTest
{
// Test Methods
}
Test 1: Search is sent after half a sec
48
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");
}
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
49
var testScheduler = new TestScheduler();
ITestableObservable<int> coldObservable = testScheduler.CreateColdObservable<int>(
OnNext<int>(20, 1),
OnNext<int>(40, 2),
OnCompleted<int>(60)
);
Test 2: first search is discarded if another search happens
50
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());
}
Summary
Pull vs. Push model
Rx operators
Building Rx queries
Rx Concurrency Model
Virtual Time
Testing Time and Concurrency with TestScheduler
51
Your headache relief pill to Asynchronous and
Event based applications
Async
Push
Triggers
Events
Reactive ExtensionsReactive Extensions
52
www.reactivex.io github.com/Reactive-Extensionswww.manning.com/dresher
Thank You
Tamir Dresher (@tamir_dresher)
53

More Related Content

What's hot

Effective testing for spark programs Strata NY 2015
Effective testing for spark programs   Strata NY 2015Effective testing for spark programs   Strata NY 2015
Effective testing for spark programs Strata NY 2015
Holden Karau
 
Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ...
Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ...Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ...
Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ...
Lucidworks
 

What's hot (20)

RxJava 2.0 介紹
RxJava 2.0 介紹RxJava 2.0 介紹
RxJava 2.0 介紹
 
Advancedservletsjsp
AdvancedservletsjspAdvancedservletsjsp
Advancedservletsjsp
 
Drools Ecosystem
Drools EcosystemDrools Ecosystem
Drools Ecosystem
 
Azure SQL Database - Connectivity Best Practices
Azure SQL Database - Connectivity Best PracticesAzure SQL Database - Connectivity Best Practices
Azure SQL Database - Connectivity Best Practices
 
ShmooCon 2009 - (Re)Playing(Blind)Sql
ShmooCon 2009 - (Re)Playing(Blind)SqlShmooCon 2009 - (Re)Playing(Blind)Sql
ShmooCon 2009 - (Re)Playing(Blind)Sql
 
Drools Introduction
Drools IntroductionDrools Introduction
Drools Introduction
 
Using xUnit as a Swiss-Aarmy Testing Toolkit
Using xUnit as a Swiss-Aarmy Testing ToolkitUsing xUnit as a Swiss-Aarmy Testing Toolkit
Using xUnit as a Swiss-Aarmy Testing Toolkit
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on Android
 
Effective testing for spark programs Strata NY 2015
Effective testing for spark programs   Strata NY 2015Effective testing for spark programs   Strata NY 2015
Effective testing for spark programs Strata NY 2015
 
Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ...
Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ...Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ...
Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ...
 
Rx 101 - Tamir Dresher - Copenhagen .NET User Group
Rx 101  - Tamir Dresher - Copenhagen .NET User GroupRx 101  - Tamir Dresher - Copenhagen .NET User Group
Rx 101 - Tamir Dresher - Copenhagen .NET User Group
 
Real-time Inverted Search in the Cloud Using Lucene and Storm
Real-time Inverted Search in the Cloud Using Lucene and StormReal-time Inverted Search in the Cloud Using Lucene and Storm
Real-time Inverted Search in the Cloud Using Lucene and Storm
 
PigSPARQL: A SPARQL Query Processing Baseline for Big Data
PigSPARQL: A SPARQL Query Processing Baseline for Big DataPigSPARQL: A SPARQL Query Processing Baseline for Big Data
PigSPARQL: A SPARQL Query Processing Baseline for Big Data
 
PuttingItAllTogether
PuttingItAllTogetherPuttingItAllTogether
PuttingItAllTogether
 
Data in Motion: Streaming Static Data Efficiently
Data in Motion: Streaming Static Data EfficientlyData in Motion: Streaming Static Data Efficiently
Data in Motion: Streaming Static Data Efficiently
 
Drools rule Concepts
Drools rule ConceptsDrools rule Concepts
Drools rule Concepts
 
Drools
DroolsDrools
Drools
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stack
 
Asegúr@IT IV - Remote File Downloading
Asegúr@IT IV - Remote File DownloadingAsegúr@IT IV - Remote File Downloading
Asegúr@IT IV - Remote File Downloading
 
Distributed Real-Time Stream Processing: Why and How 2.0
Distributed Real-Time Stream Processing:  Why and How 2.0Distributed Real-Time Stream Processing:  Why and How 2.0
Distributed Real-Time Stream Processing: Why and How 2.0
 

Similar to Testing time and concurrency Rx

Similar to Testing time and concurrency Rx (20)

Rx workshop
Rx workshopRx workshop
Rx workshop
 
Reactive Extensions: classic Observer in .NET
Reactive Extensions: classic Observer in .NETReactive Extensions: classic Observer in .NET
Reactive Extensions: classic Observer in .NET
 
Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJava
 
Shooting the Rapids
Shooting the RapidsShooting the Rapids
Shooting the Rapids
 
Tamir Dresher - Reactive Extensions (Rx) 101
Tamir Dresher - Reactive Extensions (Rx) 101Tamir Dresher - Reactive Extensions (Rx) 101
Tamir Dresher - Reactive Extensions (Rx) 101
 
Rx 101 Codemotion Milan 2015 - Tamir Dresher
Rx 101   Codemotion Milan 2015 - Tamir DresherRx 101   Codemotion Milan 2015 - Tamir Dresher
Rx 101 Codemotion Milan 2015 - Tamir Dresher
 
Design for Testability
Design for TestabilityDesign for Testability
Design for Testability
 
How to perform debounce in react
How to perform debounce in reactHow to perform debounce in react
How to perform debounce in react
 
Building responsive applications with Rx - CodeMash2017 - Tamir Dresher
Building responsive applications with Rx  - CodeMash2017 - Tamir DresherBuilding responsive applications with Rx  - CodeMash2017 - Tamir Dresher
Building responsive applications with Rx - CodeMash2017 - Tamir Dresher
 
Performance Tuning and Optimization
Performance Tuning and OptimizationPerformance Tuning and Optimization
Performance Tuning and Optimization
 
Spark Summit EU talk by Herman van Hovell
Spark Summit EU talk by Herman van HovellSpark Summit EU talk by Herman van Hovell
Spark Summit EU talk by Herman van Hovell
 
Building responsive application with Rx - confoo - tamir dresher
Building responsive application with Rx - confoo - tamir dresherBuilding responsive application with Rx - confoo - tamir dresher
Building responsive application with Rx - confoo - tamir dresher
 
Reactive Programming no Android
Reactive Programming no AndroidReactive Programming no Android
Reactive Programming no Android
 
Know your app: Add metrics to Java with Micrometer | DevNation Tech Talk
Know your app: Add metrics to Java with Micrometer | DevNation Tech TalkKnow your app: Add metrics to Java with Micrometer | DevNation Tech Talk
Know your app: Add metrics to Java with Micrometer | DevNation Tech Talk
 
Tutorial on developing a Solr search component plugin
Tutorial on developing a Solr search component pluginTutorial on developing a Solr search component plugin
Tutorial on developing a Solr search component plugin
 
Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)
 
To Study The Tips Tricks Guidelines Related To Performance Tuning For N Hib...
To Study The Tips Tricks  Guidelines Related To Performance Tuning For  N Hib...To Study The Tips Tricks  Guidelines Related To Performance Tuning For  N Hib...
To Study The Tips Tricks Guidelines Related To Performance Tuning For N Hib...
 
Angular.js Primer in Aalto University
Angular.js Primer in Aalto UniversityAngular.js Primer in Aalto University
Angular.js Primer in Aalto University
 
Umbraco - DUUGFest 17 -The need for speed
Umbraco - DUUGFest 17 -The need for speedUmbraco - DUUGFest 17 -The need for speed
Umbraco - DUUGFest 17 -The need for speed
 
Change tracking
Change trackingChange tracking
Change tracking
 

More from Tamir Dresher

More from Tamir Dresher (20)

NET Aspire - NET Conf IL 2024 - Tamir Dresher.pdf
NET Aspire - NET Conf IL 2024 - Tamir Dresher.pdfNET Aspire - NET Conf IL 2024 - Tamir Dresher.pdf
NET Aspire - NET Conf IL 2024 - Tamir Dresher.pdf
 
Tamir Dresher - DotNet 7 What's new.pptx
Tamir Dresher - DotNet 7 What's new.pptxTamir Dresher - DotNet 7 What's new.pptx
Tamir Dresher - DotNet 7 What's new.pptx
 
Tamir Dresher - What’s new in ASP.NET Core 6
Tamir Dresher - What’s new in ASP.NET Core 6Tamir Dresher - What’s new in ASP.NET Core 6
Tamir Dresher - What’s new in ASP.NET Core 6
 
Tamir Dresher - Async Streams in C#
Tamir Dresher - Async Streams in C#Tamir Dresher - Async Streams in C#
Tamir Dresher - Async Streams in C#
 
Anatomy of a data driven architecture - Tamir Dresher
Anatomy of a data driven architecture - Tamir Dresher   Anatomy of a data driven architecture - Tamir Dresher
Anatomy of a data driven architecture - Tamir Dresher
 
Tamir Dresher Clarizen adventures with the wild GC during the holiday season
Tamir Dresher   Clarizen adventures with the wild GC during the holiday seasonTamir Dresher   Clarizen adventures with the wild GC during the holiday season
Tamir Dresher Clarizen adventures with the wild GC during the holiday season
 
Debugging tricks you wish you knew Tamir Dresher - Odessa 2019
Debugging tricks you wish you knew   Tamir Dresher - Odessa 2019Debugging tricks you wish you knew   Tamir Dresher - Odessa 2019
Debugging tricks you wish you knew Tamir Dresher - Odessa 2019
 
From zero to hero with the actor model - Tamir Dresher - Odessa 2019
From zero to hero with the actor model  - Tamir Dresher - Odessa 2019From zero to hero with the actor model  - Tamir Dresher - Odessa 2019
From zero to hero with the actor model - Tamir Dresher - Odessa 2019
 
Tamir Dresher - Demystifying the Core of .NET Core
Tamir Dresher  - Demystifying the Core of .NET CoreTamir Dresher  - Demystifying the Core of .NET Core
Tamir Dresher - Demystifying the Core of .NET Core
 
Breaking the monolith to microservice with Docker and Kubernetes (k8s)
Breaking the monolith to microservice with Docker and Kubernetes (k8s)Breaking the monolith to microservice with Docker and Kubernetes (k8s)
Breaking the monolith to microservice with Docker and Kubernetes (k8s)
 
.Net december 2017 updates - Tamir Dresher
.Net december 2017 updates - Tamir Dresher.Net december 2017 updates - Tamir Dresher
.Net december 2017 updates - Tamir Dresher
 
.NET Debugging tricks you wish you knew tamir dresher
.NET Debugging tricks you wish you knew   tamir dresher.NET Debugging tricks you wish you knew   tamir dresher
.NET Debugging tricks you wish you knew tamir dresher
 
From Zero to the Actor Model (With Akka.Net) - CodeMash2017 - Tamir Dresher
From Zero to the Actor Model (With Akka.Net) - CodeMash2017 - Tamir DresherFrom Zero to the Actor Model (With Akka.Net) - CodeMash2017 - Tamir Dresher
From Zero to the Actor Model (With Akka.Net) - CodeMash2017 - Tamir Dresher
 
Debugging tricks you wish you knew - Tamir Dresher
Debugging tricks you wish you knew  - Tamir DresherDebugging tricks you wish you knew  - Tamir Dresher
Debugging tricks you wish you knew - Tamir Dresher
 
Cloud patterns - NDC Oslo 2016 - Tamir Dresher
Cloud patterns - NDC Oslo 2016 - Tamir DresherCloud patterns - NDC Oslo 2016 - Tamir Dresher
Cloud patterns - NDC Oslo 2016 - Tamir Dresher
 
Reactiveness All The Way - SW Architecture 2015 Conference
Reactiveness All The Way - SW Architecture 2015 ConferenceReactiveness All The Way - SW Architecture 2015 Conference
Reactiveness All The Way - SW Architecture 2015 Conference
 
Leveraging Dependency Injection(DI) in Universal Applications - Tamir Dresher
Leveraging Dependency Injection(DI) in Universal Applications -  Tamir DresherLeveraging Dependency Injection(DI) in Universal Applications -  Tamir Dresher
Leveraging Dependency Injection(DI) in Universal Applications - Tamir Dresher
 
Where Is My Data - ILTAM Session
Where Is My Data - ILTAM SessionWhere Is My Data - ILTAM Session
Where Is My Data - ILTAM Session
 
Azure Cloud Patterns
Azure Cloud PatternsAzure Cloud Patterns
Azure Cloud Patterns
 
Building services running on Microsoft Azure
Building services running on Microsoft AzureBuilding services running on Microsoft Azure
Building services running on Microsoft Azure
 

Recently uploaded

Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
masabamasaba
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Recently uploaded (20)

%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
Harnessing ChatGPT - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT  - Elevating Productivity in Today's Agile EnvironmentHarnessing ChatGPT  - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT - Elevating Productivity in Today's Agile Environment
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 

Testing time and concurrency Rx

  • 1. 1 Tamir Dresher (@tamir_dresher) Senior Software Architect J Testing Time and Concurrency with Rx 1
  • 2. 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 @tamir_dresher tamirdr@codevalue.net http://www.TamirDresher.com. About Me
  • 4. Reactive Extensions (Rx) Your headache relief pill to Asynchronous Event based applications Async Push Triggers Events 4
  • 6. 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 6
  • 8. 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 8
  • 12. 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*/ }); 12
  • 14. 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 14
  • 15. Observable Queries (Rx Operators) 15
  • 16. 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 16
  • 18. 1. At least 3 characters 2. Don’t overflow server (0.5 sec delay) 3. Don’t send the same string again 4. Discard results if another search was requested Reactive Search - RulesReactive Search - Rules 18
  • 19. 19
  • 20. 20
  • 21. 21 Where(s => s.Length > 2 )  
  • 22. 22 Where(s => s.Length > 2 )   Throttle(TimeSpan.FromSeconds(0.5))
  • 23. 23 Where(s => s.Length > 2 )   Throttle(TimeSpan.FromSeconds(0.5)) DistinctUntilChanged() 
  • 24. 25 Select(text => SearchAsync(text)) “REA” “REAC” Switch() “REA” results are ignored since we switched to the “REAC” results
  • 25. Abstracting Time and Concurrency 26
  • 27. 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); } 28
  • 28. // // 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 29
  • 30. // // 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 31
  • 33. Virtual Time What is time? Time can be a anything that is sequential and comparable 34 “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
  • 34. Virtual Time Scheduler 35 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> { ... }
  • 36. 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 37
  • 37. 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? 38 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
  • 38. Separating the logic from the view 39 SearchView (Presentation, Logic, State) SearchView (Presentation) SearchViewModel (Logic, State) Before After
  • 39. Separating the logic from the view 40 <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
  • 40. Separating the logic from the view – fixing the Rx query 41 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
  • 41. Injecting the Search Service client 42 public class SearchViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public SearchViewModel() { // rest of rx query } ... }
  • 42. Injecting the Search Service client 43 public class SearchViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public SearchViewModel(ISearchServiceClient searchServiceClient) { // rest of rx query } ... }
  • 43. Simple test – first try 44 [TestMethod] public void Search_OneLetterWord_NoSearchSentToService() { var fakeServiceClient = Substitute.For<ISearchServiceClient>(); var vm = new SearchViewModel(fakeServiceClient); vm.SearchTerm = "A"; fakeServiceClient.DidNotReceive().SearchAsync("A"); }
  • 44. Injecting concurrency 45 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; } }
  • 45. Injecting concurrency 46 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 */ }); }
  • 46. Simplest Rx Test Install-Package Microsoft.Reactive.Testing To simplify the Rx testing, derive your test class from ReactiveTest 47 using Microsoft.Reactive.Testing; [TestClass] public class SearchViewModelTests : ReactiveTest { // Test Methods }
  • 47. Test 1: Search is sent after half a sec 48 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"); }
  • 48. 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 49 var testScheduler = new TestScheduler(); ITestableObservable<int> coldObservable = testScheduler.CreateColdObservable<int>( OnNext<int>(20, 1), OnNext<int>(40, 2), OnCompleted<int>(60) );
  • 49. Test 2: first search is discarded if another search happens 50 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()); }
  • 50. Summary Pull vs. Push model Rx operators Building Rx queries Rx Concurrency Model Virtual Time Testing Time and Concurrency with TestScheduler 51
  • 51. Your headache relief pill to Asynchronous and Event based applications Async Push Triggers Events Reactive ExtensionsReactive Extensions 52

Editor's Notes

  1. My name is tamir dresher Im an architect from codevalue israel and a software engineering lecturer at the ruppin academic center CodeValue is a consulting company and we are also the proud development center of OzCode the amazing debugging extension for visual studio. We have a booth here at conference, so please go and check it out, youll be amazed how you lived without it. My book Rx in action is now available at Manning early access program should be published in the next few months. And that the end of my self promotion(it never hurts right?). So what are we really here for?
  2. Since .net 4