MR. Dev

Blog programisty.

Programowanie Reaktywne - Bileciki do kontroli - Unit Tests of Observer Interval.


Artykuł ten jest częścią serii artykułów na temat Programowania reaktywnego.

Zapraszam na GitHub-a.

Tematy

  1. Wstęp
  2. Zabawa z czasem - Timer
  3. Kto za tym stoi? - Scheduler
  4. Nie zapominaj - Subscribe
  5. Zabawa z czasem - Interval
  6. Zabawa z czasem - Buffer
  7. Zabawa z czasem - Delay
  8. Zabawa z czasem - Sample
  9. Zabawa z czasem - Throttle
  10. Zabawa z czasem - Timestamp/TimeInterval
  11. Tworzymy dane - Generators
  12. Tworzymy dane - Własna klasa publikująca
  13. Marudzimy - Skip
  14. Marudzimy - Take
  15. Łap To! - ConsoleKey
  16. Kombinatorzy - Concat
  17. Kombinatorzy - Repeat
  18. Kombinatorzy - Start With
  19. Kombinatorzy - Ambiguous
  20. Kombinatorzy - Merge
  21. Kombinatorzy - Zip
  22. Kombinatorzy - Switch
  23. Kombinatorzy - When-And-Then
  24. Kombinatorzy - Combine Latest
  25. Transformers - Select
  26. Transformers - OfType and Cast
  27. Transformers - Metadata
  28. Bileciki do kontroli - Unit Tests of Interval
  29. Bileciki do kontroli - Unit Tests of Observer Interval
  30. Bileciki do kontroli - Unit Tests of Create Cold/Hot Observable
  31. Szpryca - AutoFac

Wstęp

Reactive Extensions - TestScheduler 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

Reactive Extensions - UnitTest 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:


Wcześniejszy: Programowanie Reaktywne - Transformers - OfType and Cast

Następny: Programowanie Reaktywne - Bileciki do kontroli - Unit Tests of Observer Interval