Testování jednotek stavových služeb v Service Fabric

Tento článek popisuje koncepty a postupy testování jednotek stavových služeb Service Fabric. Testování jednotek v rámci Service Fabric si zaslouží vlastní úvahy, protože kód aplikace aktivně běží v různých kontextech. Tento článek popisuje postupy používané k zajištění toho, aby byl kód aplikace pokrytý v každém z různých kontextů, které může spustit.

Testování jednotek a napodobování

Testování jednotek v kontextu tohoto článku je automatizované testování, které je možné provést v kontextu test runneru, jako je MSTest nebo NUnit. Testy jednotek v tomto článku neprovádějí operace se vzdáleným prostředkem, jako je databáze nebo restful. Tyto vzdálené prostředky by měly být napodobené. Napodobení v kontextu tohoto článku bude falešné, zaznamenává a řídí návratové hodnoty pro vzdálené prostředky.

Důležité informace o Service Fabric

Testování jednotek stavové služby Service Fabric má několik aspektů. Za prvé, kód služby se spouští na více uzlech, ale v různých rolích. Testy jednotek by měly vyhodnotit kód v jednotlivých rolích, aby se dosáhlo úplného pokrytí. Různé role by byly Primární, Aktivní sekundární, Nečinná sekundární a Neznámá. Role None obvykle nepotřebuje žádné zvláštní pokrytí, protože Service Fabric tuto roli považuje za neplatnou nebo nulovou službu. Za druhé, každý uzel změní svou roli v libovolném okamžiku. Aby bylo možné dosáhnout úplného pokrytí, měly by se cesty spuštění kódu testovat se změnami rolí.

Proč stavové služby pro testování jednotek?

Stavové služby testování jednotek můžou pomoct odhalit některé běžné chyby, které by nemusely být zachyceny testováním jednotek v konvenčních aplikacích nebo konkrétních doménách. Pokud má například stavová služba nějaký stav v paměti, může tento typ testování ověřit, že je tento stav v paměti synchronizovaný napříč jednotlivými repliky. Tento typ testování může také odpovídajícím způsobem ověřit, že stavová služba reaguje na tokeny zrušení předané orchestrací Service Fabric. Při aktivaci zrušení by služba měla zastavit všechny dlouhotrvající nebo asynchronní operace.

Běžné postupy

Následující část obsahuje informace o nejběžnějších postupech pro testování jednotek stavové služby. Také radí, co by měla mít napodobovaná vrstva, aby byla těsně sladěná s orchestrací a správou stavu Service Fabric. ServiceFabric.Mocks verze 3.3.0 nebo novější je jednou z takových knihoven, která poskytuje doporučené funkce napodobování a dodržuje postupy popsané níže.

Uspořádání

Použití více instancí služby

Testy jednotek by měly spouštět více instancí stavové služby. To simuluje, co se skutečně děje v clusteru, kde Service Fabric zřídí několik replik, na kterých běží vaše služba na různých uzlech. Každá z těchto instancí se ale bude spouštějí v jiném kontextu. Při spuštění testu by každá instance měla být vybavena konfigurací rolí očekávanou v clusteru. Pokud se například očekává, že má služba cílovou velikost repliky 3, Service Fabric zřídí tři repliky na různých uzlech. Jeden z nich je primární a další dva jsou aktivní sekundární.

Ve většině případů se cesty spuštění služby pro každou z těchto rolí mírně liší. Pokud by služba například neměla přijímat požadavky od aktivní sekundární služby, může mít služba kontrolu pro tento případ, aby se vrátila informativní výjimka, která značí, že došlo k pokusu o požadavek v sekundárním objektu. Pokud máte více instancí, umožníte tuto situaci otestovat.

Více instancí navíc umožňuje testům přepnout role každé z těchto instancí, aby se ověřilo, že odpovědi jsou konzistentní i přes změny rolí.

Napodobení správce stavu

Správce stavu by se měl považovat za vzdálený prostředek, a proto by se měl napodoben. Při napodobení správce stavu musí existovat nějaké základní úložiště v paměti pro sledování toho, co je uloženo ve správci stavu, aby bylo možné je číst a ověřit. Jednoduchým způsobem, jak toho dosáhnout, je vytvořit napodobenou instanci každého z typů Reliable Collections. V rámci těchto napodobení použijte datový typ, který úzce odpovídá operacím provedeným s danou kolekcí. Následuje několik navrhovaných datových typů pro každou spolehlivou kolekci.

  • IReliableDictionary<TKey, TValue> –> System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>
  • IReliableQueue<T> –> System.Collections.Generic.Queue<T>
  • IReliableConcurrentQueue<T> –> System.Collections.Concurrent.ConcurrentQueue<T>

Mnoho instancí Správce stavu, jedno úložiště

Jak už bylo zmíněno dříve, správce stavu a spolehlivé kolekce by měly být považovány za vzdálený prostředek. Proto by se tyto prostředky měly a budou v rámci testů jednotek napodobeny. Při spouštění více instancí stavové služby ale bude obtížné udržovat každý napodobený správce stavu synchronizovaný napříč různými instancemi stavové služby. Pokud je stavová služba spuštěná v clusteru, Service Fabric se postará o zachování konzistentního správce stavu každé sekundární repliky s primární replikou. Proto by se testy měly chovat stejně, aby mohly simulovat změny rolí.

Jednoduchým způsobem, jak této synchronizace dosáhnout, je použít jednotný vzor pro podkladový objekt, který ukládá data zapsaná do každé Reliable Collection. Například pokud stavová služba používá .IReliableDictionary<string, string> Napodobený správce stavu by měl vrátit napodobenou .IReliableDictionary<string, string> Tento napodobení může používat ke ConcurrentDictionary<string, string> sledování zapsaných párů klíč/hodnota. Parametr ConcurrentDictionary<string, string> by měl být singleton používaný všemi instancemi správců stavu předaných službě.

Sledování tokenů zrušení

Tokeny zrušení jsou důležitým, ale často přehlíženým aspektem stavových služeb. Když Service Fabric spustí primární repliku stavové služby, poskytne se token zrušení. Účelem tohoto tokenu zrušení je signalizovat službě, když je odebrána nebo degradována na jinou roli. Stavová služba by měla zastavit všechny dlouhotrvající nebo asynchronní operace, aby Service Fabric mohl dokončit pracovní postup změny role.

Při spouštění testů jednotek by se měly během provádění testu uchovávat všechny tokeny zrušení, které jsou k dispozici pro runAsync, ChangeRoleAsync, OpenAsync a CloseAsync. Podržení těchto tokenů umožní testu simulovat vypnutí nebo snížení úrovně služby a ověřit, jestli služba správně reaguje.

Kompletní testování pomocí napodobených vzdálených prostředků

Testy jednotek by měly spouštět co nejvíce kódu aplikace, které můžou změnit stavové služby. Doporučuje se, aby testy byly ucelenější. Jedinými napodobeními, které existují, jsou zaznamenávání, simulace nebo ověřování interakcí se vzdálenými prostředky. To zahrnuje interakce se správcem stavu a spolehlivými kolekcemi. Následující fragment kódu je příkladem gherkin pro test, který demonstruje kompletní testování:

	Given stateful service named "fabric:/MyApp/MyService" is created
	And a new replica is created as "Primary" with id "111"
	And a new replica is created as "IdleSecondary" with id "222"
    And a new replica is created as "IdleSecondary" with id "333"
	And all idle secondary replicas are promoted to active secondary
	When a request is made to add the an employee "John Smith"
    And the active secondary replica "222" is promoted to primary
    And a request is made to get all employees
	Then the request should should return the "John Smith" employee

Tento test ověří, že data zachycená na jedné replice jsou při povýšení na primární repliku k dispozici sekundární replice. Za předpokladu, že spolehlivá kolekce je záložní úložiště pro data zaměstnanců, Aa potenciální selhání, která by mohla být zachycena s tímto testem, je, pokud kód aplikace nebyl spuštěn CommitAsync v transakci uložit nového zaměstnance. V takovém případě druhá žádost o získání zaměstnanců nevrátí zaměstnance přidaného první žádostí.

Jednající

Napodobování orchestrace replik Service Fabric

Při správě více instancí služeb by testy měly inicializovat a odstranit tyto služby stejným způsobem jako orchestrace Service Fabric. Například při vytvoření služby na nové primární replice Service Fabric vyvolá CreateServiceReplicaListener, OpenAsync, ChangeRoleAsync a RunAsync. Události životního cyklu jsou popsány v následujících článcích:

Spuštění změn role repliky

Testy jednotek by měly měnit role instancí služby stejným způsobem jako orchestrace Service Fabric. Počítač stavu role je zdokumentován v následujícím článku:

Počítač stavu role repliky

Simulace změn rolí je jedním z nejdůležitějších aspektů testování a může odhalit problémy, kdy stav repliky není konzistentní. Nekonzistentní stav repliky může nastat kvůli ukládání stavu v paměti do statických proměnných instance nebo na úrovni třídy. Příkladem mohou být tokeny zrušení, výčty a konfigurační objekty/hodnoty. Tím se také zajistí, že služba respektuje tokeny zrušení poskytnuté během runAsync, aby mohla dojít ke změně role. Simulace změn rolí může také odhalit problémy, ke kterým může dojít v případě, že kód není napsaný tak, aby umožňoval vícenásobné vyvolání runAsync.

Zrušení tokenů zrušení

Měly by existovat testy jednotek, ve kterých se zruší token zrušení poskytnutý runAsync. To umožní testu ověřit, že se služba řádně vypne. Během tohoto vypnutí by měly být zastaveny všechny dlouhotrvající nebo asynchronní operace. Příkladem dlouhotrvajícího procesu, který může existovat ve službě, je proces, který naslouchá zprávám ve spolehlivé frontě. To může existovat přímo v rámci RunAsync nebo vlákna na pozadí. Implementace by měla obsahovat logiku pro ukončení operace, pokud je tento token zrušení zrušen.

Pokud stavové služby využívají jakoukoli mezipaměť nebo stav v paměti, který by měl existovat pouze na primárním serveru, měly by být v tuto chvíli odstraněny. To má zajistit, aby byl tento stav konzistentní, pokud se uzel později znovu stane primárním. Testování zrušení umožní testu ověřit, že je tento stav odstraněn správně.

Spouštění požadavků na více replik

Kontrolní testy by měly provést stejný požadavek na různé repliky. Při spárování se změnami rolí je možné odhalit problémy s konzistencí. Ukázkový test může provést následující kroky:

  1. Provedení požadavku na zápis na aktuální primární server
  2. Spusťte požadavek na čtení, který vrátí data zapsaná v kroku 1 vůči aktuálnímu primárnímu serveru.
  3. Zvýšení úrovně sekundární na primární. To by také mělo snížit aktuální primární na sekundární.
  4. Proveďte stejný požadavek na čtení z kroku 2 vůči nové sekundární databázi.

V posledním kroku může test potvrdit, že vrácená data jsou konzistentní. Potenciálním problémem, který by to mohlo odhalit, je to, že data vrácená službou můžou být v paměti, ale v konečném důsledku mohou být zajištěna spolehlivou kolekcí. Tato data v paměti se nemusí správně synchronizovat s tím, co existuje ve spolehlivé kolekci.

Data v paměti se obvykle používají k vytvoření sekundárních indexů nebo agregací dat, která existují ve spolehlivé kolekci.

Uplatňování

Zajištění shody odpovědí napříč replikami

Testy jednotek by měly potvrdit, že odpověď na daný požadavek je konzistentní napříč několika replikami po přechodu na primární. To může vést k potenciálním problémům, kdy data zadaná v odpovědi buď nejsou spolehlivá kolekce, nebo se uchovávají v paměti bez mechanismu synchronizace těchto dat mezi replikami. Tím se zajistí, že služba bude po obnovení rovnováhy nebo převzetí služeb při selhání service fabric do nové primární repliky odesílat konzistentní odpovědi.

Ověření, že služba respektuje zrušení

Dlouhotrvající nebo asynchronní procesy, které by se měly ukončit při zrušení tokenu zrušení, by se měly ověřit, že se po zrušení skutečně ukončily. Tím zajistíte, že navzdory měnícím se rolím repliky se procesy, které nemají běžet na jiné než primární replice, před dokončením přechodu zastaví. To může také odhalit problémy, kdy takový proces blokuje dokončení žádosti o změnu nebo vypnutí role ze služby Service Fabric.

Ověřte, které repliky by měly obsluhovat požadavky.

Testy by měly potvrdit očekávané chování, pokud je požadavek směrován na neprimární repliku. Service Fabric poskytuje možnost, aby sekundární repliky obsluhovaly požadavky. Zápisy do spolehlivých kolekcí však mohou probíhat pouze z primární repliky. Pokud vaše aplikace chce, aby požadavky obsluhovaly pouze primární repliky nebo sekundární může zpracovávat pouze podmnožinu požadavků, měly by testy potvrdit očekávané chování v pozitivních i negativních případech. Negativní případ, kterým je požadavek, je směrován na repliku, která by požadavek neměla zpracovat, a pozitivní případ je opakem.

Další kroky

Naučte se , jak testovat stavové služby.