Artykuł ten jest częścią serii artykułów na temat Programowania reaktywnego.
Zapraszam na GitHub-a.
Tematy
- Wstęp
- Zabawa z czasem - Timer
- Kto za tym stoi? - Scheduler
- Nie zapominaj - Subscribe
- Zabawa z czasem - Interval
- Zabawa z czasem - Buffer
- Zabawa z czasem - Delay
- Zabawa z czasem - Sample
- Zabawa z czasem - Throttle
- Zabawa z czasem - Timestamp/TimeInterval
- Tworzymy dane - Generators
- Tworzymy dane - Własna klasa publikująca
- Marudzimy - Skip
- Marudzimy - Take
- Łap To! - ConsoleKey
- Kombinatorzy - Concat
- Kombinatorzy - Repeat
- Kombinatorzy - Start With
- Kombinatorzy - Ambiguous
- Kombinatorzy - Merge
- Kombinatorzy - Zip
- Kombinatorzy - Switch
- Kombinatorzy - When-And-Then
- Kombinatorzy - Combine Latest
- Transformers - Select
- Transformers - OfType and Cast
- Transformers - Metadata
- Bileciki do kontroli - Unit Tests of Interval
- Bileciki do kontroli - Unit Tests of Observer Interval
- Bileciki do kontroli - Unit Tests of Create Cold/Hot Observable
- Szpryca - AutoFac
Wstęp
Dzisiaj postanowiłem kontynuować wczorajszą tematykę. Czyli testowanie. W przypadku Rx-ów nie jest to takie proste. Ze względu na potrzebę kontroli nad procesem publikowania danych na strumień. Jedna z metod została opisana w poprzednim poście. Dzisiaj nieco inny cel testów.
TestScheduler.Start
Sam test nie czego sobie ładny i klarowny, dzięki zrzucie śmieci do osobnej klasy: IntervalObserverTestsFixture. Ustawiamy dzisiejszych bohaterów czyli:
- created - sekunda w której ma nastąpić utworzenie producenta treści,
- subscribed - w tej jednostce czasu następuje zapis na strumień (fikcyjny),
- disposed - w jakim czasie nastąpi zakończenie działalności dystrybutora.
Oczywiście wszystkie wartości powinny być w tej samej jednostce: sekunda.
1
2
3
4
5
6
7
8
9
10
11
12
13
//arrange
_fixture.SetSimulationData(created, subscribed, disposed);
//act
var result = act();
//assert__simulation_notification
_fixture.assert__simulation_notification(result);
}
private IList<Recorded<Notification<long>>> act()
{
return _fixture.act();
Po przygotowaniu wykonujemy test, i zwrotnie otrzymujemy nagranie z przebiegu działalności dystrybutora. Czarna skrzynka, i stenogramy;).
Możemy wówczas sprawdzić jak wyglądała historia strumyczka.
1
2
3
4
5
6
7
8
9
10
public void SetSimulationData(int created, int subscribed, int disposed)
{
_disposed = disposed;
_created = created;
_subscribed = subscribed;
var period = TimeSpan.FromSeconds(1);
_sourceObservableInterval = Observable.Interval(period, _testScheduler)
.Take(_disposed);
Oczywiście przy tworzeniu strumienia musimy podać TestScheduler, tak jak w poprzednim poście. Ucinamy do testów ilość publikowanej treści przy pomocy .Take.
Wprowadzone wartości sekundowe będą potrzebne w metodzie testującej poniżej.
1
2
3
4
5
6
7
8
public IList<Recorded<Notification<long>>> act()
{
var notificationRecorded = _testScheduler.Start(() => _sourceObservableInterval,
TimeSpan.FromSeconds(_created).Ticks,
TimeSpan.FromSeconds(_subscribed).Ticks,
TimeSpan.FromSeconds(_disposed).Ticks);
return notificationRecorded.Messages;
A tutaj już dzieje się, przy pomocy operatora Start określamy o jakim czasie ma nastąpić dane działanie: created, subscribed, disposed.
Dzięki zastosowaniu interwału wyzwalania publikacji danych nas strumień co 1s możemy także tutaj posługiwać się wartościami całkowitymi. Jednak metoda Start przyjmuje wartości typu TimeStamp. Jest też na samym szczycie wywołania rodzynek, lambda na utworzony wcześniej strumień: _sourceObservableInterval.
Na koniec co innego pozostało jak sprawdzić czy wszystko zachowało się prawidłowo. Należy powołać komisję śledczą na czele z Shouldly i zbadać zawartość czarnej skrzynki.
1
2
3
4
5
6
7
8
9
var shouldBeValue = _disposed - 1;
shouldBeValue -= _subscribed;
result.Count.ShouldBe(shouldBeValue);
long index = 0;
foreach (var item in result)
{
item.Value.Value.ShouldBe(index++);
W pierwszej asercji sprawdzamy ilość zachowanych publikacji na strumień, powinno ich być o 1 mniej niż ustalona ilość pobranych wartości ze strumienia (gdyż, jako ostatni przychodzi OnCompleted).
Sprawdzić należy także dane jakie są dostarczane do odbiorców. Do tego potrzebne było podwójne użycie Value.Value, gdyż pierwszy Value zawiera w sobie nazwę metody jaka została wywołana. Temat poruszany w rozdziale o metadanych.
Zakończenie
Testowanie Rx-ów to dość specyficzny temat, i warto by było jak naj mnie korzystać z takich testów. Dlatego warto było by odseparować w możliwy jak największy sposób logikę dotykaną przez odbiorców treści do osobnych klas. Dobrym tutaj podejściem było by pisanie testów przed implementacją, i nawet nie korzystanie z samych właściwości Rx-owych.
Niech kod będzie z Wami!.
Jest to post wchodzący w skład podjętego wyzwania ogłoszonego przez MIROBURN we vlogu z dnia 3 lutego 2018 roku.
Celem wyzwania jest systematyczne działanie w ciągu 30 dni.
Postanowiłem pisać post dziennie o tematyce Programowania Reaktywnego dla platformy .NET.
Wszelkie źródła związane z postami znajdują się na repozytorium GitHub.
Stan obecny wyzwania: 30 z 30 dni.
Referencje:
- MSDN - Getting Started with Rx,
- MSDN - Reactive Extensions,
- 101 Rx Samples,
- ReactiveX,
- Code Project,
- GitHub
Wcześniejszy: Programowanie Reaktywne - Transformers - OfType and Cast
Następny: Programowanie Reaktywne - Bileciki do kontroli - Unit Tests of Observer Interval