Unit Testing Enterprise Apps
Poznámka:
Tato elektronická kniha byla publikována na jaře roku 2017 a od té doby nebyla aktualizována. Existuje mnoho v knize, která zůstává cenná, ale některé materiály jsou zastaralé.
Mobilní aplikace mají jedinečné problémy, které se nemusí starat o desktopové a webové aplikace. Mobilní uživatelé se budou lišit podle zařízení, která používají, podle síťového připojení, dostupnosti služeb a řady dalších faktorů. Mobilní aplikace by proto měly být testovány tak, jak budou použity ve skutečném světě ke zlepšení jejich kvality, spolehlivosti a výkonu. Existuje mnoho typů testování, které by se mělo provádět v aplikaci, včetně testování částí, testování integrace a testování uživatelského rozhraní, přičemž testování částí je nejběžnější formou testování.
Test jednotek přijímá malou jednotku aplikace, obvykle metodu, izoluje ji od zbytku kódu a ověřuje, že se chová podle očekávání. Jejím cílem je zkontrolovat, že každá jednotka funkcí funguje podle očekávání, aby se chyby nešířily v celé aplikaci. Zjištění chyby, ve které k ní dochází, je efektivnější, když dochází k nepřímému výskytu chyby v sekundárním bodě selhání.
Testování částí má největší vliv na kvalitu kódu, pokud je nedílnou součástí pracovního postupu vývoje softwaru. Jakmile byla metoda zapsána, měly by být zapsány testy jednotek, které ověřují chování metody v reakci na standardní, hraniční a nesprávné případy vstupních dat a kontrolují explicitní nebo implicitní předpoklady provedené kódem. Alternativně při vývoji řízeném testem se testy jednotek zapisují před kódem. V tomto scénáři fungují testy jednotek jako dokumentace k návrhu i funkční specifikace.
Poznámka:
Testy jednotek jsou velmi efektivní proti regresi – to znamená funkce, které se používají k práci, ale byly narušeny chybnou aktualizací.
Testy jednotek obvykle používají model arrange-act-assert:
- Oddíl uspořádání metody testu jednotek inicializuje objekty a nastaví hodnotu dat, která jsou předána metodě v rámci testu.
- Oddíl act vyvolá metodu test s požadovanými argumenty.
- Oddíl assert ověřuje, že akce metody v testu se chová podle očekávání.
Provedením tohoto modelu zajistíte, aby testy jednotek byly čitelné a konzistentní.
Injektáž závislostí a testování částí
Jednou z motivací k přijetí volně propojených architektur je, že usnadňuje testování jednotek. Jedním z typů registrovaných v autofacu OrderService
je třída. Následující příklad kódu ukazuje osnovu této třídy:
public class OrderDetailViewModel : ViewModelBase
{
private IOrderService _ordersService;
public OrderDetailViewModel(IOrderService ordersService)
{
_ordersService = ordersService;
}
...
}
Třída OrderDetailViewModel
má závislost na IOrderService
typu, který kontejner přeloží při vytvoření instance objektu OrderDetailViewModel
. Místo vytvoření objektu OrderService
pro testování OrderDetailViewModel
třídy místo toho nahraďte OrderService
objekt napodobenou pro účely testů. Tento vztah znázorňuje obrázek 10–1.
Obrázek 10-1: Třídy, které implementují rozhraní IOrderService
Tento přístup umožňuje OrderService
předání objektu OrderDetailViewModel
do třídy za běhu a v zájmu testovatelnosti umožňuje OrderMockService
, aby třída byla předána OrderDetailViewModel
do třídy v testovací době. Hlavní výhodou tohoto přístupu je, že umožňuje provádět testy jednotek, aniž by vyžadovaly nepraktné prostředky, jako jsou webové služby nebo databáze.
Testování aplikací MVVM
Testování modelů a zobrazení modelů z aplikací MVVM je stejné jako testování jiných tříd a stejné nástroje a techniky , jako je testování jednotek a napodobování, je možné použít. Existují však některé vzory, které jsou typické pro model a zobrazení tříd modelu, které mohou těžit z konkrétních technik testování jednotek.
Tip
Otestujte jednu věc s každým testem jednotek. Nenechte se pokoušet, aby cvičení testu jednotek bylo více než jeden aspekt chování jednotky. To vede k testům, které se obtížně čtou a aktualizují. Může také vést k nejasnostem při interpretaci selhání.
Mobilní aplikace eShopOnContainers provádí testování jednotek, která podporuje dva různé typy testů jednotek:
- Fakta jsou testy, které jsou vždy pravdivé, což testuje neutrální podmínky.
- Teorie jsou testy, které platí pouze pro konkrétní sadu dat.
Testy jednotek, které jsou součástí mobilní aplikace eShopOnContainers, jsou testy faktů, takže každá metoda testování jednotek je zdobena atributem [Fact]
.
Poznámka:
Testy xUnit provádí spouštěč testů. Pokud chcete spustit spouštěč testů, spusťte projekt eShopOnContainers.TestRunner pro požadovanou platformu.
Testování asynchronních funkcí
Při implementaci modelu MVVM modely zobrazení obvykle vyvolávají operace ve službách, často asynchronně. Testy kódu, který tyto operace vyvolá, obvykle používají napodobení jako nahrazení skutečných služeb. Následující příklad kódu ukazuje testování asynchronní funkce předáním napodobené služby do modelu zobrazení:
[Fact]
public async Task OrderPropertyIsNotNullAfterViewModelInitializationTest()
{
var orderService = new OrderMockService();
var orderViewModel = new OrderDetailViewModel(orderService);
var order = await orderService.GetOrderAsync(1, GlobalSetting.Instance.AuthToken);
await orderViewModel.InitializeAsync(order);
Assert.NotNull(orderViewModel.Order);
}
Tento test jednotek zkontroluje, že Order
vlastnost OrderDetailViewModel
instance bude mít hodnotu po InitializeAsync
vyvolání metody. Metoda InitializeAsync
je vyvolána při přechodu na odpovídající zobrazení modelu zobrazení. Další informace o navigaci naleznete v tématu Navigace.
OrderDetailViewModel
Když je instance vytvořena, očekáváOrderService
, že instance bude zadána jako argument. Načítá OrderService
ale data z webové služby. OrderMockService
Proto je instance, která je napodobenou verzí OrderService
třídy, určena jako argument konstruktoruOrderDetailViewModel
. Když se pak vyvolá metoda modelu InitializeAsync
zobrazení, která vyvolá IOrderService
operace, načte se napodobení dat místo komunikace s webovou službou.
Testování implementace INotifyPropertyChanged
INotifyPropertyChanged
Implementace rozhraní umožňuje zobrazení reagovat na změny, které pocházejí ze zobrazení modelů a modelů. Tyto změny nejsou omezeny na data zobrazená v ovládacích prvcích – slouží také k řízení zobrazení, jako jsou stavy modelu zobrazení, které způsobují spuštění animací nebo zakázání ovládacích prvků.
Vlastnosti, které lze aktualizovat přímo testem jednotek, lze testovat připojením obslužné rutiny události k PropertyChanged
události a kontrolou, zda je událost vyvolána po nastavení nové hodnoty vlastnosti. Následující příklad kódu ukazuje takový test:
[Fact]
public async Task SettingOrderPropertyShouldRaisePropertyChanged()
{
bool invoked = false;
var orderService = new OrderMockService();
var orderViewModel = new OrderDetailViewModel(orderService);
orderViewModel.PropertyChanged += (sender, e) =>
{
if (e.PropertyName.Equals("Order"))
invoked = true;
};
var order = await orderService.GetOrderAsync(1, GlobalSetting.Instance.AuthToken);
await orderViewModel.InitializeAsync(order);
Assert.True(invoked);
}
Tento test jednotek vyvolá InitializeAsync
metodu OrderViewModel
třídy, která způsobí aktualizaci jeho Order
vlastnosti. Test jednotek projde za předpokladu PropertyChanged
, že je událost vyvolána Order
pro vlastnost.
Testování komunikace založené na zprávách
Prohlédněte si modely, které používají MessagingCenter
třídu ke komunikaci mezi volně propojenými třídami, lze testovat tak, že se přihlásíte k odběru zprávy, kterou odešle testovaný kód, jak je znázorněno v následujícím příkladu kódu:
[Fact]
public void AddCatalogItemCommandSendsAddProductMessageTest()
{
bool messageReceived = false;
var catalogService = new CatalogMockService();
var catalogViewModel = new CatalogViewModel(catalogService);
Xamarin.Forms.MessagingCenter.Subscribe<CatalogViewModel, CatalogItem>(
this, MessageKeys.AddProduct, (sender, arg) =>
{
messageReceived = true;
});
catalogViewModel.AddCatalogItemCommand.Execute(null);
Assert.True(messageReceived);
}
Tento test jednotek zkontroluje, že CatalogViewModel
publikuje AddProduct
zprávu v reakci na spuštění AddCatalogItemCommand
. Vzhledem k tomu, že MessagingCenter
třída podporuje odběry zpráv vícesměrového vysílání, test jednotek se může přihlásit k odběru AddProduct
zprávy a spustit delegáta zpětného volání v reakci na jeho přijetí. Tento delegát zpětného volání zadaný jako výraz lambda nastaví boolean
pole, které používá Assert
příkaz k ověření chování testu.
Testování zpracování výjimek
Testy jednotek lze také zapsat, které kontrolují, že konkrétní výjimky jsou vyvolány pro neplatné akce nebo vstupy, jak je znázorněno v následujícím příkladu kódu:
[Fact]
public void InvalidEventNameShouldThrowArgumentExceptionText()
{
var behavior = new MockEventToCommandBehavior
{
EventName = "OnItemTapped"
};
var listView = new ListView();
Assert.Throws<ArgumentException>(() => listView.Behaviors.Add(behavior));
}
Tento test jednotek vyvolá výjimku, protože ListView
ovládací prvek nemá událost s názvem OnItemTapped
. Metoda Assert.Throws<T>
je obecná metoda, kde T
je typ očekávané výjimky. Argument předaný Assert.Throws<T>
metodě je výraz lambda, který vyvolá výjimku. Proto bude test jednotek úspěšný za předpokladu, že výraz lambda vyvolá ArgumentException
.
Tip
Vyhněte se psaní testů jednotek, které prověřují řetězce zpráv o výjimce. Řetězce zpráv o výjimkách se můžou v průběhu času měnit, takže testy jednotek, které spoléhají na jejich přítomnost, se považují za křehké.
Testování ověřování
Existují dva aspekty testování implementace ověřování: testování, že jsou správně implementována všechna ověřovací pravidla, a testování, že ValidatableObject<T>
třída funguje podle očekávání.
Logika ověřování je obvykle jednoduchá k testování, protože se obvykle jedná o samostatný proces, ve kterém výstup závisí na vstupu. Měly by existovat testy na výsledcích vyvolání Validate
metody pro každou vlastnost, která má alespoň jedno přidružené ověřovací pravidlo, jak je znázorněno v následujícím příkladu kódu:
[Fact]
public void CheckValidationPassesWhenBothPropertiesHaveDataTest()
{
var mockViewModel = new MockViewModel();
mockViewModel.Forename.Value = "John";
mockViewModel.Surname.Value = "Smith";
bool isValid = mockViewModel.Validate();
Assert.True(isValid);
}
Tento test jednotek zkontroluje, že ověření proběhne úspěšně, pokud obě ValidatableObject<T>
vlastnosti v MockViewModel
instanci mají data.
Kromě kontroly úspěšného ověření by testy ověřovacích jednotek měly také zkontrolovat hodnoty Value
, IsValid
a Errors
vlastnost každé ValidatableObject<T>
instance, a ověřit, že třída funguje podle očekávání. Následující příklad kódu ukazuje test jednotek, který to dělá:
[Fact]
public void CheckValidationFailsWhenOnlyForenameHasDataTest()
{
var mockViewModel = new MockViewModel();
mockViewModel.Forename.Value = "John";
bool isValid = mockViewModel.Validate();
Assert.False(isValid);
Assert.NotNull(mockViewModel.Forename.Value);
Assert.Null(mockViewModel.Surname.Value);
Assert.True(mockViewModel.Forename.IsValid);
Assert.False(mockViewModel.Surname.IsValid);
Assert.Empty(mockViewModel.Forename.Errors);
Assert.NotEmpty(mockViewModel.Surname.Errors);
}
Tento test jednotek zkontroluje, že ověření selže, pokud Surname
vlastnost neobsahuje žádná data, a IsValid
Value
, a vlastnost každé Errors
ValidatableObject<T>
instance jsou správně nastavenyMockViewModel
.
Shrnutí
Test jednotek přijímá malou jednotku aplikace, obvykle metodu, izoluje ji od zbytku kódu a ověřuje, že se chová podle očekávání. Jejím cílem je zkontrolovat, že každá jednotka funkcí funguje podle očekávání, aby se chyby nešířily v celé aplikaci.
Chování objektu v testu lze izolovat nahrazením závislých objektů napodobením objektů, které simulují chování závislých objektů. To umožňuje provádět testy jednotek, aniž by vyžadovaly nepraktné prostředky, jako jsou webové služby nebo databáze.
Testování modelů a zobrazení modelů z aplikací MVVM je stejné jako testování všech ostatních tříd a stejné nástroje a techniky lze použít.