Sdílet prostřednictvím


Testování částí

Tip

Tento obsah je výňatek z elektronické knihy, vzory podnikových aplikací pomocí .NET MAUI, dostupné na .NET Docs nebo jako zdarma ke stažení PDF, které lze číst offline.

Vzory podnikových aplikací pomocí úvodní miniatury eBooku .NET MAUI

U aplikací s více platformami dochází k problémům podobným desktopovým i webovým aplikacím. Mobilní uživatelé se budou lišit podle svých zařízení, síťového připojení, dostupnosti služeb a různých dalších faktorů. Aplikace pro více platforem by proto měly být testovány tak, jak by se používaly ve skutečném světě ke zlepšení kvality, spolehlivosti a výkonu. V aplikaci by se mělo provádět mnoho typů testování, včetně testování částí, testování integrace a testování uživatelského rozhraní. Testování jednotek je nejběžnější forma a základní pro vytváření vysoce kvalitních aplikací.

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í, takže chyby se nešířijí v celé aplikaci. Zjištění chyby, ke které dochází, je efektivnější než pozorování účinku chyby nepřímo 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. Testy jednotek můžou fungovat jako dokumentace k návrhu a funkční specifikace pro aplikaci. Jakmile je metoda zapsána, testy jednotek by měly být zapsány, které ověřují chování metody v reakci na standardní, hraniční a nesprávné případy vstupních dat a zkontrolují explicitní nebo implicitní předpoklady provedené kódem. Alternativně při vývoji řízeném testem se testy jednotek zapisují před kódem. Další informace o vývoji řízeném testy a o tom, jak ho implementovat, najdete v tématu Návod: Vývoj řízený testy pomocí Průzkumníka testů.

Poznámka:

Testy jednotek jsou velmi účinné proti regresi. To znamená, že funkce, které fungovaly, ale byly narušeny chybnou aktualizací.

Testy jednotek obvykle používají model arrange-act-assert:

Krok Popis
Uspořádat Inicializuje objekty a nastaví hodnotu dat, která jsou předána metodě v rámci testu.
Jednat Vyvolá metodu v rámci testu s požadovanými argumenty.
Assert Ověřuje, že se akce metody v rámci testu chová podle očekávání.

Tento model zajišťuje, že testy jednotek jsou čitelné, samopopisující a konzistentní.

Injektáž závislostí a testování jednotek

Jednou z motivací k přijetí volně propojených architektur je, že usnadňuje testování jednotek. Jedním z typů registrovaných ve službě injektáž závislostí je IAppEnvironmentService rozhraní. Následující příklad kódu ukazuje osnovu této třídy:

public class OrderDetailViewModel : ViewModelBase
{
    private IAppEnvironmentService _appEnvironmentService;

    public OrderDetailViewModel(
        IAppEnvironmentService appEnvironmentService,
        IDialogService dialogService, INavigationService navigationService, ISettingsService settingsService)
        : base(dialogService, navigationService, settingsService)
    {
        _appEnvironmentService = appEnvironmentService;
    }
}

Třída OrderDetailViewModel má závislost na IAppEnvironmentService typu, který kontejner injektáž závislostí přeloží při vytvoření instance objektu OrderDetailViewModel . Místo vytvoření objektu IAppEnvironmentService , který využívá skutečné servery, zařízení a konfigurace k testování OrderDetailViewModel třídy, místo toho nahraďte IAppEnvironmentService objekt napodobeným objektem pro účely testů. Napodobený objekt je objekt, který má stejný podpis objektu nebo rozhraní, ale je vytvořen určitým způsobem, který pomáhá s testováním jednotek. Často se používá s injektáží závislostí k poskytování konkrétních implementací rozhraní pro testování různých scénářů dat a pracovních postupů.

Tento přístup umožňuje IAppEnvironmentService předání objektu OrderDetailViewModel do třídy za běhu a v zájmu testovatelnosti umožňuje předání OrderDetailViewModel do třídy v testovacím čase do třídy. Hlavní výhodou tohoto přístupu je, že umožňuje provádět testy jednotek, aniž by vyžadovaly nepraktné prostředky, jako jsou funkce platformy runtime, webové služby nebo databáze.

Testování aplikací MVVM

Testování modelů a zobrazení modelů z aplikací MVVM je stejné jako testování jakékoli jiné třídy a používá stejné nástroje a techniky; to zahrnuje funkce, jako je testování jednotek a napodobování. Některé vzory, které jsou typické pro modelování a zobrazení tříd modelů, však mohou těžit z konkrétních technik testování jednotek.

Tip

Otestujte jednu věc s každým testem jednotek. S rozšířením složitosti testu je ověření tohoto testu obtížnější. Omezením testu jednotek na jeden problém můžeme zajistit, aby naše testy byly opakovatelnější, izolované a měly menší dobu provádění. Další osvědčené postupy pro testování částí s .NET najdete v tématu Osvědčené postupy.

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í.

Multiformní aplikace eShop používá msTest k testování jednotek, která podporuje dva různé typy testů jednotek:

Typ testování Atribut Popis
TestMethod TestMethod Definuje skutečnou testovací metodu, která se má spustit.
DataSource DataSource Testy, které platí pouze pro konkrétní sadu dat.

Testy jednotek, které jsou součástí multiformní aplikace eShop, jsou TestMethod, takže každá metoda testování jednotek je zdobena atributem TestMethod . Kromě MSTest existuje několik dalších testovacích architektur, včetně NUnit a xUnit.

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í:

[TestMethod]
public async Task OrderPropertyIsNotNullAfterViewModelInitializationTest()
{
    // Arrange
    var orderService = new OrderMockService();
    var orderViewModel = new OrderDetailViewModel(orderService);

    // Act
    var order = await orderService.GetOrderAsync(1, GlobalSetting.Instance.AuthToken);
    await orderViewModel.InitializeAsync(order);

    // Assert
    Assert.IsNotNull(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áIOrderService, že instance bude zadána jako argument. Načítá OrderService ale data z webové služby. OrderMockService Proto instance, napodobení verze OrderService třídy, je určen jako argument konstruktoruOrderDetailViewModel. Potom se načtou napodobená data místo komunikace s webovou službou při vyvolání metody modelu InitializeAsync zobrazení, která používá IOrderService operace.

Testování implementací 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:

[TestMethod]
public async Task SettingOrderPropertyShouldRaisePropertyChanged()
{
    var 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.IsTrue(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, je možné 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:

[TestMethod]
public void AddCatalogItemCommandSendsAddProductMessageTest()
{
    var messageReceived = false;
    var catalogService = new CatalogMockService();
    var catalogViewModel = new CatalogViewModel(catalogService);

    MessagingCenter.Subscribe<CatalogViewModel, CatalogItem>(
        this, MessageKeys.AddProduct, (sender, arg) =>
    {
        messageReceived = true;
    });
    catalogViewModel.AddCatalogItemCommand.Execute(null);

    Assert.IsTrue(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í logické pole používané příkazem Assert 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:

[TestMethod]
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 všechna ověřovací pravidla jsou správně implementována a testuje, ž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:

[TestMethod]
public void CheckValidationPassesWhenBothPropertiesHaveDataTest()
{
    var mockViewModel = new MockViewModel();
    mockViewModel.Forename.Value = "John";
    mockViewModel.Surname.Value = "Smith";

    var isValid = mockViewModel.Validate();

    Assert.IsTrue(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, IsValida 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á:

[TestMethod]
public void CheckValidationFailsWhenOnlyForenameHasDataTest()
{
    var mockViewModel = new MockViewModel();
    mockViewModel.Forename.Value = "John";

    bool isValid = mockViewModel.Validate();

    Assert.IsFalse(isValid);
    Assert.IsNotNull(mockViewModel.Forename.Value);
    Assert.IsNull(mockViewModel.Surname.Value);
    Assert.IsTrue(mockViewModel.Forename.IsValid);
    Assert.IsFalse(mockViewModel.Surname.IsValid);
    Assert.AreEqual(mockViewModel.Forename.Errors.Count(), 0);
    Assert.AreNotEqual(mockViewModel.Surname.Errors.Count(), 0);
}

Tento test jednotek zkontroluje, že ověření selže, pokud Surname vlastnost neobsahuje žádná data, a IsValidValue, 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í, takže chyby se nešířijí 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 se vyžadovaly nepraktné prostředky, jako jsou funkce platformy runtime, 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.