Skip to content

Fluent Assertions - Assertion Scope használata

Published: at 00:00

Assertion Scope

Bizonyos teszteknél előfordul, hogy sok állítás/ellenőrzés található ezeknek a végén és probléma esetén ilyenkor nem látjuk valójában mennyit rontottunk. Az alapvető működés az, hogy a teszt az első hibára futó ellenőrzés után megáll és ebből fakadóan nem látjuk a következő problémát, ha van ilyen. Amennyiben ezt elkerülnénk lehetőségünk van bizonyos eszközök esetén úgynevezett scope-ba rakni ezeket az ellenőrző részeket. Ennek az az előnye, hogy nem fog megállni a teszt futása az első bukott ellenőrzéskor, hanem folytatja a többivel és a végén megkapunk minden információt. A lényeg, hogy ezzel a módszerrel elkerülhetjük azt, hogy a teszt finomítása, javítása után látjuk csak a következő üzenetet. Ehhez én a Fluent Assertion csomagot szoktam használni, de ez a funkcionalitás megtalálható másikban is (pl. NUnit). Nekem ez leginkább integrációs teszteknél szokott jól jönni.

Annak, aki nem ismeri a Fluent Assertions-t és az ehhez hasonló csomagokat annak röviden a lényegük az, hogy ezek használatával informatívabb hibaüzenetekhez lehet jutni bukott tesztek esetén.

Nézzük meg az alábbi példát:

public class User
{
    public int Id { get; set; }

    public string FullName { get; set; }

    public IEnumerable<Address> Addresses { get; set; }
}

A teszten belül pedig ez látható:

// ACT
User user = GetUserById(1);

// ASSERT
using (var scope = new AssertionScope())
{
    user.Should().NotBeNull();
    user.Id.Should().Be(1);
    user.FullName.Should().Be("Teszt Elek");
    user.Addresses.Should().NotBeNull();
    user.Addresses.Should().HaveCount(3);
}
Expected user.FullName to be 
"Teszt Elek" with a length of 10, but 
"Munka Pál" has a length of 9, differs near "Mun" (index 0).
Expected user.Addresses not to be <null>.
Expected user.Addresses to contain 3 item(s), but found <null>.

Anélkül, hogy látnánk a kódot pontosan meg tudjuk mondani, hogy mi is a probléma és azonnal nem csak azt kezdhetjük nézni, hogy miért is lett más a felhasználó neve, hanem azt is, hogy a címek között miért nincs egyetlen elem sem. Persze ez csak egy kicsi példa, ahol nem nagy probléma ha az egyik hiba kijavítása után szembesülnénk a következővel.

További lehetőségek

Plusz információ hozzáadása a AssertionScope-hoz

Bukott tesztek esetén van lehetőség a scope által adott eredménynek a végéhez további információkat hozzátenni az AddReportable metódust használva. Ebben az esetben egy kulcsot és egy értéket vár.

scope.AddReportable("Additional information","User test");
scope.AddReportable("Another information", "User test 2");

Ebben az esetben a kimenet az alábbi lesz:

Message: 
  Expected user.FullName to be 
  "Teszt Elek" with a length of 10, but 
  "Munka Pál" has a length of 9, differs near "Mun" (index 0).
  ...

  With Additional information:
  User test
  With Another information:
  User test2

Ezeket inkább integrációs teszteknél találtam hasznosnak, mert olyankor jött jól, hogy bukott teszt esetén ezzel hozzá tudtam tenni valami plusz információt. Természetesen a test outputra bármikor lehet írni, de az mindig kiíródik, az AddReportable-ben megadottakkal ellentétben.

Objektumok hozzáadása a AssertionScope-hoz

Ezt csak említés szintjén hozom fel, mert ez egy olyan funkció amit sosem használtam és nem is éreztem úgy, hogy szükségem lenne rá. Van lehetőség objektumokat hozzáadni a scope-hoz az AddNonReportable metódus használatával (string key, object value paraméterezéssel), amihez tartozik egy Get<T>(key) metódus az objektum kinyeréséhez (hatóköre az adott és a hozzá tartozó beágyazott scope-ok).

AssertionScope állapota

Az alábbi kóddal lehetőség van lekérdezni egy scope állapotát. Ennek segítségével könnyen egyedi kóddal kiegészíthetjük a tesztünkben az ellenőrzési részt, aminek lefutása függ az állapottól.

bool hasFailures = scope.HasFailures();

Scope elnevezése és a WithExpectation metódus

A létrehozott scope-nak adhatunk nevet. Ez történhet a konstruktor paraméterével, vagy a scope Context változója használatával. Ebben az esetben minden üzenetnek a scope-on belül a megadott név fog szerepelni a változó neve helyén. Ezzel nekem személy szerint az volt a problémám, hogy ilyenkor elveszítem pont azt az értékes információt, hogy mivel is van gond.

var scope = new AssertionScope("User test")

Az első üzenetet ha megnézzük látható hogy User test lett a user.FullName helyett.

Expected User test to be 
    "Teszt Elek" with a length of 10, but 
    "Munka Pál" has a length of 9, differs near "Mun" (index 0).

A fenti elnevezés helyett ajánlom inkább a WithExpectation metódust aminek string paramétere minden üzenet elé oda fog kerülni. Tartozik hozzá egy ClearExpectation metódus is, ami ahogyan neve is sugallja az Expectationt törli a scope-ról így a további üzenetek esetén nem fog már megjelenni.

scope.WithExpectation("Addresses expectations: ");
user.Addresses.Should().NotBeNull();
scope.ClearExpectation();
user.Addresses.Should().HaveCount(3);
Addresses expectations: Expected user.Addresses not to be <null>.
Expected user.Addresses to contain 3 item(s), but found <null>.

Több scope és nested scope

A Fluent Assertions tudja kezelni a több scope és a scope a scope-ban helyzetet is. A lenti példa eredménye ugyanaz mint eddig lesz mint eddig.

using (var scope = new AssertionScope())
{
    user.Should().NotBeNull();
    user.Id.Should().Be(1);
    user.FullName.Should().Be("Teszt Elek");

    using (var nestedScope = new AssertionScope())
    {
        user.Addresses.Should().NotBeNull();
        user.Addresses.Should().HaveCount(3);
    }
}

Módosítsuk meg ezt egy kicsit:

using (var scope = new AssertionScope())
{
    user.Should().NotBeNull();
    user.Id.Should().Be(1);
    user.FullName.Should().Be("Teszt Elek");

    using (var nestedScope = new AssertionScope().WithExpectation("Addresses count should be 3: "))
    {
        user.Addresses.Should().NotBeNull();
        user.Addresses.Should().HaveCount(3);
    }
}

A WithExpectation metódus használatával például el lehet különíteni a scope-on belüli üzeneteket. Ebben az esetben a kimeneten az alábbi lesz látható:

Message: 
    Expected user.FullName to be 
    "Teszt Elek" with a length of 10, but 
    "Munka Pál" has a length of 9, differs near "Mun" (index 0).
    Addresses count should be 3: Expected user.Addresses not to be <null>.
    Addresses count should be 3: Expected user.Addresses to contain 3 item(s), but found <null>.

Végezetül

Talán sikerült körbejárni ezt a funkcióját a Fluent Assertions csomagnak. Mindenképpen szeretném megemlíteni, hogy a weboldalukon található dokumentáció nem túl részletgazdag. Talán ez valamennyire érthető is annak fényében, hogy az alap működése is teljesen megfelel az AssertionScope-nak. Nagyon ritkán kell ennél több.


Previous Post
Getter only property - Mi lesz belőle?
Next Post
Teszt példányok előállítása (AutoFixture, Bogus, NBuilder) alapok