Udostępnij za pośrednictwem


Testowanie jednostkowe aplikacji dla przedsiębiorstw

Uwaga

Ta książka elektroniczna została opublikowana wiosną 2017 r. i od tego czasu nie została zaktualizowana. Jest wiele w książce, która pozostaje cenna, ale niektóre z materiałów są przestarzałe.

Aplikacje mobilne mają unikatowe problemy, które aplikacje klasyczne i internetowe nie muszą się martwić. Użytkownicy mobilni będą różnić się od urządzeń, z których korzystają, przez łączność sieciową, przez dostępność usług i szereg innych czynników. W związku z tym aplikacje mobilne powinny być testowane, ponieważ będą używane w świecie rzeczywistym w celu poprawy jakości, niezawodności i wydajności. Istnieje wiele typów testów, które należy wykonać w aplikacji, w tym testy jednostkowe, testowanie integracji i testowanie interfejsu użytkownika, a testowanie jednostkowe jest najbardziej typową formą testowania.

Test jednostkowy wykonuje małą jednostkę aplikacji, zazwyczaj metodę, izoluje ją od pozostałej części kodu i sprawdza, czy zachowuje się zgodnie z oczekiwaniami. Jego celem jest sprawdzenie, czy każda jednostka funkcjonalności działa zgodnie z oczekiwaniami, aby błędy nie propagowały się w całej aplikacji. Wykrywanie usterki, w której występuje, jest bardziej wydajne, aby zaobserwować efekt usterki pośrednio w pomocniczym punkcie awarii.

Testowanie jednostkowe ma największy wpływ na jakość kodu, gdy jest integralną częścią przepływu pracy tworzenia oprogramowania. Po zapisaniu metody należy napisać testy jednostkowe, które weryfikują zachowanie metody w odpowiedzi na standardowe, granice i nieprawidłowe przypadki danych wejściowych oraz czy sprawdzają wszelkie jawne lub niejawne założenia dokonane przez kod. Alternatywnie, w przypadku programowania opartego na testach, testy jednostkowe są zapisywane przed kodem. W tym scenariuszu testy jednostkowe działają zarówno jako dokumentacja projektowa, jak i specyfikacje funkcjonalne.

Uwaga

Testy jednostkowe są bardzo skuteczne w odniesieniu do regresji — czyli funkcje używane do pracy, ale zostały zakłócone przez wadliwą aktualizację.

Testy jednostkowe zwykle używają wzorca rozmieszczania asertywnego:

  • Sekcja rozmieszczania metody testu jednostkowego inicjuje obiekty i ustawia wartość danych przekazywanych do metody testowanej.
  • Sekcja act wywołuje metodę testową z wymaganymi argumentami.
  • Sekcja asercji sprawdza, czy działanie metody testowej działa zgodnie z oczekiwaniami.

Zgodnie z tym wzorcem gwarantuje, że testy jednostkowe są czytelne i spójne.

Wstrzykiwanie zależności i testowanie jednostkowe

Jedną z motywacji do przyjęcia luźno powiązanej architektury jest to, że ułatwia testowanie jednostkowe. Jednym z typów zarejestrowanych w usłudze Autofac jest OrderService klasa . Poniższy przykład kodu przedstawia konspekt tej klasy:

public class OrderDetailViewModel : ViewModelBase  
{  
    private IOrderService _ordersService;  

    public OrderDetailViewModel(IOrderService ordersService)  
    {  
        _ordersService = ordersService;  
    }  
    ...  
}

Klasa OrderDetailViewModel ma zależność od IOrderService typu, który kontener rozpoznaje, gdy tworzy wystąpienie OrderDetailViewModel obiektu. Jednak zamiast tworzyć obiekt do testowania jednostkowego OrderServiceOrderDetailViewModel klasy, zamiast tego zastąp OrderService obiekt pozorem na potrzeby testów. Rysunek 10–1 ilustruje tę relację.

Classes that implement the IOrderService interface

Rysunek 10–1. Klasy implementujące interfejs IOrderService

Takie podejście umożliwia OrderService przekazanie obiektu do OrderDetailViewModel klasy w czasie wykonywania, a w interesie możliwości testowania umożliwia OrderMockService przekazanie klasy do OrderDetailViewModel klasy w czasie testowania. Główną zaletą tego podejścia jest to, że umożliwia wykonywanie testów jednostkowych bez konieczności używania niezłych zasobów, takich jak usługi internetowe lub bazy danych.

Testowanie aplikacji MVVM

Testowanie modeli i wyświetlanie modeli z aplikacji MVVM jest identyczne z testowaniem innych klas, a można używać tych samych narzędzi i technik, takich jak testowanie jednostkowe i pozorowanie. Istnieją jednak pewne wzorce typowe dla klas modelu i wyświetlania modeli, które mogą korzystać z określonych technik testowania jednostkowego.

Napiwek

Przetestuj jedną rzecz przy użyciu każdego testu jednostkowego. Nie należy kusić do wykonania ćwiczenia testowego jednostkowego więcej niż jednego aspektu zachowania jednostki. W ten sposób prowadzi do testów, które są trudne do odczytania i aktualizacji. Może to również prowadzić do nieporozumień podczas interpretowania błędu.

Aplikacja mobilna eShopOnContainers wykonuje testy jednostkowe, które obsługują dwa różne typy testów jednostkowych:

  • Fakty to testy, które są zawsze prawdziwe, które testują niezmienne warunki.
  • Teorie to testy, które są prawdziwe tylko dla określonego zestawu danych.

Testy jednostkowe dołączone do aplikacji mobilnej eShopOnContainers są testami faktów, a więc każda metoda testu jednostkowego jest ozdobiona atrybutem [Fact] .

Uwaga

Testy xUnit są wykonywane przez moduł uruchamiający testy. Aby wykonać moduł uruchamiający testy, uruchom projekt eShopOnContainers.TestRunner dla wymaganej platformy.

Testowanie funkcji asynchronicznych

Podczas implementowania wzorca MVVM wyświetlanie modeli zwykle wywołuje operacje na usługach, często asynchronicznie. Testy kodu, który wywołuje te operacje, zwykle używają makiety jako zamienników dla rzeczywistych usług. W poniższym przykładzie kodu pokazano testowanie funkcji asynchronicznych przez przekazanie makiety usługi do modelu widoku:

[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);  
}

Ten test jednostkowy sprawdza, czy Order właściwość OrderDetailViewModel wystąpienia będzie miała wartość po InitializeAsync wywołaniu metody. Metoda InitializeAsync jest wywoływana po przejściu do odpowiedniego widoku modelu widoku. Aby uzyskać więcej informacji na temat nawigacji, zobacz Nawigacja.

Po utworzeniu OrderDetailViewModel wystąpienia oczekuje OrderService się, że wystąpienie zostanie określone jako argument. OrderService Pobiera jednak dane z usługi internetowej. W związku z OrderMockService tym wystąpienie, które jest pozorną wersją OrderService klasy, jest określane jako argument konstruktora OrderDetailViewModel . Następnie po wywołaniu metody modelu InitializeAsync widoku, która wywołuje operacje IOrderService , pobierane są pozorne dane zamiast komunikować się z usługą internetową.

Testowanie implementacji INotifyPropertyChanged

Zaimplementowanie interfejsu INotifyPropertyChanged umożliwia widokom reagowanie na zmiany pochodzące z modeli i modeli widoku. Te zmiany nie są ograniczone do danych wyświetlanych w kontrolkach — są one również używane do kontrolowania widoku, takich jak stany modelu wyświetlania, które powodują uruchomienie animacji lub wyłączenie kontrolek.

Właściwości, które można zaktualizować bezpośrednio przez test jednostkowy, można przetestować, dołączając program obsługi zdarzeń do PropertyChanged zdarzenia i sprawdzając, czy zdarzenie jest wywoływane po ustawieniu nowej wartości dla właściwości. Poniższy przykład kodu przedstawia taki 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);  
}

Ten test jednostkowy wywołuje metodę InitializeAsyncOrderViewModel klasy, co powoduje zaktualizowanie jej Order właściwości. Test jednostkowy zakończy się pomyślnie, pod warunkiem, że PropertyChanged zdarzenie zostanie zgłoszone dla Order właściwości .

Testowanie komunikacji opartej na komunikatach

Wyświetlanie modeli używających MessagingCenter klasy do komunikowania się między luźno powiązanymi klasami może być testowane jednostkowo przez subskrybowanie komunikatu wysyłanego przez testowany kod, jak pokazano w poniższym przykładzie kodu:

[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);  
}

Ten test jednostkowy sprawdza, czy CatalogViewModel komunikat jest publikowany AddProduct w odpowiedzi na jego AddCatalogItemCommand wykonanie. MessagingCenter Ponieważ klasa obsługuje subskrypcje komunikatów multiemisji, test jednostkowy może subskrybować AddProduct komunikat i wykonywać delegat wywołania zwrotnego w odpowiedzi na jego odbieranie. Ten delegat wywołania zwrotnego określony jako wyrażenie lambda ustawia boolean pole używane przez Assert instrukcję w celu zweryfikowania zachowania testu.

Testowanie obsługi wyjątków

Testy jednostkowe można również napisać, aby sprawdzić, czy określone wyjątki są zgłaszane dla nieprawidłowych akcji lub danych wejściowych, jak pokazano w poniższym przykładzie kodu:

[Fact]  
public void InvalidEventNameShouldThrowArgumentExceptionText()  
{  
    var behavior = new MockEventToCommandBehavior  
    {  
        EventName = "OnItemTapped"  
    };  
    var listView = new ListView();  

    Assert.Throws<ArgumentException>(() => listView.Behaviors.Add(behavior));  
}

Ten test jednostkowy zgłosi wyjątek, ponieważ kontrolka ListView nie ma zdarzenia o nazwie OnItemTapped. Metoda Assert.Throws<T> jest metodą ogólną, w której T jest typem oczekiwanego wyjątku. Argument przekazany do Assert.Throws<T> metody jest wyrażeniem lambda, które zgłosi wyjątek. W związku z tym test jednostkowy przejdzie pod warunkiem, że wyrażenie lambda zgłasza ArgumentExceptionwartość .

Napiwek

Unikaj pisania testów jednostkowych, które badają ciągi komunikatów o wyjątku. Ciągi komunikatów wyjątków mogą ulec zmianie w czasie, a więc testy jednostkowe, które polegają na ich obecności, są uważane za kruche.

Sprawdzanie poprawności testowania

Istnieją dwa aspekty testowania implementacji walidacji: testowanie, czy wszystkie reguły walidacji są prawidłowo implementowane, i testowanie, czy ValidatableObject<T> klasa działa zgodnie z oczekiwaniami.

Logika walidacji jest zwykle prosta do przetestowania, ponieważ zazwyczaj jest to proces samodzielny, w którym dane wyjściowe zależą od danych wejściowych. Powinny istnieć testy dotyczące wyników wywoływania Validate metody dla każdej właściwości, która ma co najmniej jedną skojarzną regułę walidacji, jak pokazano w poniższym przykładzie kodu:

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

    bool isValid = mockViewModel.Validate();  

    Assert.True(isValid);  
}

Ten test jednostkowy sprawdza, czy walidacja zakończy się powodzeniem, gdy obie ValidatableObject<T> właściwości w wystąpieniu MockViewModel mają dane.

Oprócz sprawdzania, czy weryfikacja zakończy się pomyślnie, testy jednostkowe weryfikacji powinny również sprawdzać wartości Valuewłaściwości , IsValidi Errors każdego ValidatableObject<T> wystąpienia, aby sprawdzić, czy klasa działa zgodnie z oczekiwaniami. W poniższym przykładzie kodu pokazano test jednostkowy, który wykonuje następujące czynności:

[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);  
}

Ten test jednostkowy sprawdza, czy sprawdzanie poprawności kończy się niepowodzeniem, gdy Surname właściwość MockViewModel obiektu nie ma żadnych danych, a Valuewłaściwość , IsValidi Errors każdego ValidatableObject<T> wystąpienia jest poprawnie ustawiona.

Podsumowanie

Test jednostkowy wykonuje małą jednostkę aplikacji, zazwyczaj metodę, izoluje ją od pozostałej części kodu i sprawdza, czy zachowuje się zgodnie z oczekiwaniami. Jego celem jest sprawdzenie, czy każda jednostka funkcjonalności działa zgodnie z oczekiwaniami, aby błędy nie propagowały się w całej aplikacji.

Zachowanie obiektu testowanego można odizolować, zastępując obiekty zależne obiektami pozorowanymi, które symulują zachowanie obiektów zależnych. Dzięki temu testy jednostkowe mogą być wykonywane bez konieczności używania nieporętnych zasobów, takich jak usługi internetowe lub bazy danych.

Testowanie modeli i wyświetlanie modeli z aplikacji MVVM jest identyczne z testowaniem innych klas, a te same narzędzia i techniki mogą być używane.