Megosztás a következőn keresztül:


Egységtesztelés

Tipp.

Ez a tartalom a 'Enterprise Application Patterns Using .NET' e-könyvből vett részlet, amely elérhető a MAUI oldalon, vagy ingyenesen letölthető PDF-ként, amit offline is lehet olvasni.

MAUI eBook cover thumbnail.

A többplatformos alkalmazások az asztali és a webes alkalmazásokhoz hasonló problémákat tapasztalnak. A mobilfelhasználók az eszközüktől, a hálózati kapcsolattól, a szolgáltatások elérhetőségétől és más tényezőktől függően eltérőek lesznek. Ezért a többplatformos alkalmazásokat úgy kell tesztelni, ahogy a való világban használnák a minőség, a megbízhatóság és a teljesítmény javítása érdekében. Számos tesztelési típust kell elvégezni egy alkalmazáson, beleértve az egységtesztelést, az integrációs tesztelést és a felhasználói felület tesztelését. Az egységtesztelés a leggyakoribb forma, és elengedhetetlen a kiváló minőségű alkalmazások létrehozásához.

Az egységteszt az alkalmazás egy kis egységét, általában egy metódust vesz igénybe, elkülöníti a kód többi részétől, és ellenőrzi, hogy a várt módon viselkedik-e. A cél annak ellenőrzése, hogy minden egyes funkcióegység a várt módon működik-e, így a hibák nem propagálásra kerülnek az alkalmazás egészében. A hibák észlelése, ahol előfordul, hatékonyabb, mint egy hiba közvetett hatásának megfigyelése másodlagos meghibásodási ponton.

Az egységtesztelés a kódminőségre a legfontosabb hatással van, ha ez a szoftverfejlesztési munkafolyamat szerves része. Az egységtesztek egy alkalmazás tervezési dokumentációjaként és funkcionális specifikációjaként is működhetnek. Amint megírtak egy metódust, olyan egységteszteket kell írni, amelyek ellenőrzik a metódus viselkedését a standard, a határ- és a helytelen bemeneti adatesetekre reagálva, és ellenőrzik a kód által tett explicit vagy implicit feltételezéseket. Másik lehetőségként a tesztalapú fejlesztéssel az egységtesztek a kód előtt lesznek megírva. A tesztalapú fejlesztéssel és annak implementálásával kapcsolatos további információkért lásd útmutatót: Tesztalapú fejlesztés a Test Explorer használatával..

Megjegyzés

Az egységtesztek nagyon hatékonyak a regresszió ellen. Ez azt a funkciót tartalmazza, amely korábban működött, de egy hibás frissítés megzavarta.

Az egységtesztek általában az előkészítés-végrehajtás-ellenőrzés mintát használják.

Lépés Leírás
Elrendezés Inicializálja az objektumokat, és beállítja a vizsgált metódusnak átadott adatok értékét.
Felvonás Meghívja a vizsgált metódust a szükséges argumentumokkal.
Állít Ellenőrzi, hogy a vizsgált módszer működése a várt módon működik-e.

Ez a minta biztosítja, hogy az egységtesztek olvashatók, önleírók és konzisztensek legyenek.

Függőséginjektálás és egységtesztelés

A lazán összekapcsolt architektúra bevezetésének egyik motivációja az, hogy megkönnyíti az egységtesztelést. A függőséginjektálási szolgáltatásban regisztrált egyik típus az IAppEnvironmentService interfész. Az alábbi példakód az osztály vázlatát mutatja be:

public class OrderDetailViewModel : ViewModelBase
{
    private IAppEnvironmentService _appEnvironmentService;

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

Az OrderDetailViewModel osztály függ a típustól IAppEnvironmentService , amelyet a függőséginjektálási tároló felold, amikor létrehoz egy OrderDetailViewModel objektumot. Azonban ahelyett, hogy valódi kiszolgálókat, eszközöket és konfigurációkat használó objektumot hoz létre IAppEnvironmentService az OrderDetailViewModel osztály teszteléséhez, ehelyett cserélje le az IAppEnvironmentService objektumot egy szimulált objektumra a tesztek céljára. A makettobjektum olyan objektum, amely azonos aláírással rendelkezik egy objektumhoz vagy felülethez, de meghatározott módon jön létre az egységteszteléshez. A függőséginjektálással gyakran használják a különböző adatok és munkafolyamat-forgatókönyvek teszteléséhez szükséges interfészek konkrét implementációinak biztosítására.

Ez a megközelítés lehetővé teszi, hogy az IAppEnvironmentService objektum futásidőben átkerüljön az OrderDetailViewModel osztályba, és a tesztelhetőség érdekében lehetővé teszi, hogy a próbaosztályt a tesztelési időpontban átadják az OrderDetailViewModel osztálynak. Ennek a megközelítésnek a fő előnye, hogy lehetővé teszi az egységtesztek végrehajtását anélkül, hogy nem megfelelő erőforrásokat, például futtatókörnyezeti platformfunkciókat, webszolgáltatásokat vagy adatbázisokat kellene igényelnie.

MVVM-alkalmazások tesztelése

A modellek tesztelése és az MVVM-alkalmazásokból származó modellek megtekintése megegyezik bármely más osztály tesztelésével, és ugyanazokat az eszközöket és technikákat használja; Ez olyan funkciókat is tartalmaz, mint az egységtesztelés és a gúnyolás. A modellosztályok modellezésére és megtekintésére jellemző minták némelyike azonban kihasználhatja az egyes egységtesztelési technikákat.

Tipp.

Minden egységteszttel egy dolgot tesztelhet. A teszt összetettsége egyre összetettebbé válik, ami megnehezíti a teszt ellenőrzését. Az egységtesztek egyetlen problémára való korlátozásával biztosíthatjuk, hogy a tesztjeink ismételhetőbbek, elszigeteltebbek legyenek, és kisebb végrehajtási idő legyen. További ajánlott eljárásokért tekintse meg a .NET ajánlott tesztelési eljárásait.

Ne legyen kísértés arra, hogy az egységtesztelés az egység viselkedésének egynél több aspektusát is gyakorolja. Ez olyan tesztekhez vezet, amelyek nehezen olvashatók és frissíthetők. A hiba értelmezése során zavart is okozhat.

Az eShop többplatformos alkalmazás MSTest használatával végzi el az egységtesztelést, amely két különböző egységtesztet támogat:

Tesztelési típus Attribútum Leírás
TesztMódszer TestMethod Meghatározza a futtatandó tényleges tesztmetódust.
Adatforrás DataSource Olyan tesztek, amelyek csak egy adott adatkészletre igazak.

Az eShop többplatformos alkalmazáshoz tartozó egységtesztek TestMethod-ek, így minden egységteszt metódust az TestMethod attribútummal van ellátva. Az MSTest mellett számos más tesztelési keretrendszer is elérhető, köztük az NUnit és az xUnit.

Aszinkron funkciók tesztelése

Az MVVM-minta megvalósításakor a nézetmodellek általában szolgáltatásokon hajtanak végre műveleteket, gyakran aszinkron módon. Az ezeket a műveleteket meghívó kódtesztek általában a tényleges szolgáltatások utánzatait használják. Az alábbi példakód bemutatja az aszinkron funkciók tesztelését, ha egy modellszolgáltatást egy nézetmodellbe ad át:

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

Ez az egységteszt ellenőrzi, hogy a OrderOrderDetailViewModel példány tulajdonsága rendelkezik-e értékkel a InitializeAsync metódus meghívása után. A InitializeAsync metódus akkor lesz meghívva, ha a nézetmodell megfelelő nézetére navigál. A navigációval kapcsolatos további információkért lásd : Navigáció.

OrderDetailViewModel A példány létrehozásakor elvárja, hogy egy IOrderService példány argumentumként legyen megadva. A OrderService lekéri az adatokat egy webszolgáltatásból. Ezért egy OrderMockService osztály modellezett verziója, azaz egy OrderService példány, van megadva az OrderDetailViewModel konstruktor argumentumaként. Ebben az esetben tesztadatok kerülnek lekérésre, ahelyett hogy a nézetmodell metódusának InitializeAsync meghívásakor a webszolgáltatással kommunikálnának, amely IOrderService műveleteket használ.

INotifyPropertyChanged implementációk tesztelése

Az interfész implementálása lehetővé teszi, hogy a INotifyPropertyChanged nézetek reagáljanak a nézetmodellekből és modellekből származó változásokra. Ezek a módosítások nem korlátozódnak a vezérlőkben megjelenített adatokra – a nézet vezérlésére is használhatók, például az animációkat kiváltó nézetmodell-állapotok vagy a vezérlők letiltására.

Az egységteszt által közvetlenül frissíthető tulajdonságokat úgy lehet tesztelni, hogy egy eseménykezelőt csatol az PropertyChanged eseményhez, és ellenőrzi, hogy az esemény létrejön-e a tulajdonság új értékének beállítása után. Az alábbi példakód egy ilyen tesztet mutat be:

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

Ez az egységteszt meghívja a(z) InitializeAsync osztály OrderViewModel metódusát, amely a Order tulajdonságának frissítését eredményezi. Az egységteszt sikeres lesz, feltéve, hogy az PropertyChanged esemény a Order tulajdonsághoz kapcsolódik.

Üzenetalapú kommunikáció tesztelése

Az osztályt MessagingCenter lazán összekapcsolt osztályok közötti kommunikációra használó modelleket a tesztelt kód által küldött üzenetre való feliratkozással lehet tesztelni, ahogyan az a következő kód példájában is látható:

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

Ez az egységteszt ellenőrzi, hogy a rendszer a CatalogViewModel végrehajtásra AddProduct válaszul közzéteszi-e az AddCatalogItemCommand üzenetet. Mivel az osztály támogatja a MessagingCenter csoportos küldésű üzenet-előfizetéseket, az egységteszt előfizethet az AddProduct üzenetre, és válaszul végrehajthat egy visszahívási függvényt. Ez a lambda kifejezésként megadott visszahívási delegált beállít egy logikai mezőt, amelyet az Assert utasítás a teszt viselkedésének ellenőrzésére használ.

Kivételkezelés tesztelése

Az egységtesztek azt is megírhatják, hogy a rendszer bizonyos kivételeket ad-e érvénytelen műveletekhez vagy bemenetekhez, ahogy az a következő kód példájában is látható:

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

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

Ez az egységteszt kivételt fog dobni, mert a ListView vezérlőnek nincs olyan eseménye, amelynek neve OnItemTapped. A Assert.Throws<T> metódus egy általános metódus, amely T a várt kivétel típusát adja meg. A metódusnak Assert.Throws<T> átadott argumentum egy lambda kifejezés, amely kivételt eredményez. Ezért az egységteszt sikeres lesz, ha a lambda kifejezés egy ArgumentException dob.

Tipp.

Kerülje a kivételüzenet-sztringeket vizsgáló egységtesztek írását. A kivételüzenetek szövegei idővel változhatnak, ezért azok az egységtesztek, amelyek a jelenlétükre támaszkodnak, törékenynek tekinthetők.

Tesztelési validálás

Az érvényesítési implementáció tesztelésének két aspektusa van: annak tesztelése, hogy az ellenőrzési szabályok megfelelően vannak-e implementálva, és hogy az osztály a ValidatableObject<T> várt módon végez-e tesztelést.

Az érvényesítési logika tesztelése általában egyszerű, mivel általában egy önálló folyamat, amelyben a kimenet a bemenettől függ. Tesztelni kell a metódus meghívásának Validate eredményeit minden olyan tulajdonságon, amely rendelkezik legalább egy társított érvényesítési szabvással, ahogy az a következő kód példájában is látható:

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

    var isValid = mockViewModel.Validate();

    Assert.IsTrue(isValid);
}

Ez az egységteszt ellenőrzi, hogy az ellenőrzés sikeres-e, amikor a ValidatableObject<T> példányban lévő két MockViewModel tulajdonság mindkettő rendelkezik adatokkal.

Az ellenőrzés sikerességének igazolása mellett az érvényesítési egységteszteknek a Value, IsValid és Errors tulajdonságok értékeit is ellenőrizniük kell az egyes ValidatableObject<T> példányok esetében, hogy igazolják, az osztály a várt módon működik. Az alábbi példakód egy egységtesztet mutat be, amely ezt teszi:

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

Ez az egységteszt ellenőrzi, hogy az ellenőrzés sikertelen-e, ha a Surname tulajdonságnál a MockViewModel nem rendelkezik adatokkal, és az egyes Value példányoknál a IsValid, Errors és ValidatableObject<T> tulajdonságok helyesen vannak beállítva.

Összegzés

Az egységteszt az alkalmazás egy kis egységét, általában egy metódust vesz igénybe, elkülöníti a kód többi részétől, és ellenőrzi, hogy a várt módon viselkedik-e. A cél annak ellenőrzése, hogy minden egyes funkcióegység a várt módon működik-e, így a hibák nem propagálásra kerülnek az alkalmazás egészében.

A vizsgált objektumok viselkedése elkülöníthető úgy, hogy a függő objektumokat a függő objektumok viselkedését szimuláló modellobjektumokra cseréli. Ez lehetővé teszi az egységtesztek végrehajtását anélkül, hogy nem megfelelő erőforrásokat, például futtatókörnyezeti platformfunkciókat, webszolgáltatásokat vagy adatbázisokat kellene megkövetelni

A modellek tesztelése és az MVVM-alkalmazásokból származó modellek megtekintése megegyezik a többi osztály tesztelésével, és ugyanazokat az eszközöket és technikákat használhatja.