Jak na čitelnější testy: odstraňování zbytečných hodnot

Od Petr Zemek, 2021-04-03

Rychlý tip, jak zčitelnit testy pomocí odstranění hodnot, které v testu nejsou potřeba.

Původní kód

Mějme následující dva testy:

def test_is_admin_returns_true_when_user_has_admin_role():
    user = User(
        name='František Veselý',
        birth_date=Date(1985, 30, 11),
        address=Address('Jiráskova', 225, 'Rokycany', 33701),
        email='frantisek.vesely@gmail.com',
        phone='+420608123456',
        roles=['admin'],
        preferences=UserPreferences(
            theme='light',
            timezone='Europe/Berlin',
        ),
    )
 
    assert user.is_admin()
 
def test_is_admin_returns_false_when_user_does_not_have_admin_role():
    user = User(
        name='František Veselý',
        birth_date=Date(1985, 30, 11),
        address=Address('Jiráskova', 225, 'Rokycany', 33701),
        email='frantisek.vesely@gmail.com',
        phone='+420608123456',
        roles=[],
        preferences=UserPreferences(
            theme='light',
            timezone='Europe/Berlin',
        ),
    )
 
    assert not user.is_admin()

Zkuste si tyto dva testy projít, pochopit, a pak pokračovat ve čtení.

Proč takto ne?

Oba testy obsahují hodnoty, které z hlediska testu nejsou vůbec potřeba. Obecně, testy by měly obsahovat pouze potřebný kód. Pokud je v testu kód, který můžete upravit či zrušit, aniž by to mělo na test vliv, tak je to typický příznak toho, že se jedná o nepotřebnou hodnotu. Programátor, který se snaží test pochopit se pak musí prokousat množstvím balastu, což jednak zdržuje, a jednak to odvádí pozornost.

Další nevýhodou je, že pokud do třídy User přidáme nový atribut, tak musíme upravit množství testů, i když tento atribut vůbec nepotřebují. Recenzent koukající se na diff takového pull requestu se bude určitě divit, proč se kvůli přidání nového atributu muselo měnit tolik testů.

Jak to udělat lépe?

Vytvořením pomocné funkce, která se postará o vytvoření uživatele na základě předaných hodnot s tím, že za nezadané hodnoty doplní jakékoliv výchozí hodnoty. Testy pak budou mnohem čitelnější:

def test_is_admin_returns_true_when_user_has_admin_role():
    user = any_user(roles=['admin'])
 
    assert user.is_admin()
 
def test_is_admin_returns_false_when_user_does_not_have_admin_role():
    user = any_user(roles=[])
 
    assert not user.is_admin()

Další výhoda je ta, že testy budou typicky odolnější vůči změnám, např. přidání nového atributu do třídy User.

Obsah tohoto pole je soukromý a nebude veřejně zobrazen.

Filtrované HTML (využíváno)

  • Povolené HTML značky: <a href hreflang> <em> <strong> <cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <table>
  • Zvýraznění syntaxe kódu lze povolit přes následující značky: <code>, <blockcode>, <bash>, <c>, <cpp>, <haskell>, <html>, <java>, <javascript>, <latex>, <perl>, <php>, <python>, <ruby>, <rust>, <sql>, <text>, <vim>, <xml>, <yaml>.
  • Řádky a odstavce se zalomí automaticky.
  • Webové a e-mailové adresy jsou automaticky převedeny na odkazy.
CAPTCHA
8 + 3 =
Vyřešte tento jednoduchý matematický příklad a vložte výsledek. Např. pro 1+3 vložte 4.
Nějak se mi tady rozmohl spam, takže poprosím o ověření.