Gyakorlat

Befejeződött

Ebben a gyakorlatban a Pytest használatával tesztel egy függvényt. Ezután megkereshet és kijavíthat néhány lehetséges problémát a függvénysel kapcsolatban, amelyek sikertelen teszteket okoznak. A hibák vizsgálata és a Pytest részletes hibajelentésének használata elengedhetetlen a problémás tesztek vagy hibák azonosításához és javításához az éles kódban.

Ebben a gyakorlatban egy úgynevezett admin_command() függvényt használunk, amely bemenetként elfogad egy rendszerparancsot, és opcionálisan előtagot ad az sudo eszközhöz. A függvénynek van egy hibája, amelyet tesztek írásával fedezhet fel.

1. lépés – A gyakorlathoz tartozó teszteket tartalmazó fájl hozzáadása

  1. A Python fájlnév-konvencióit használva a tesztfájlokhoz hozzon létre egy új tesztfájlt. Nevezze el a tesztfájlt test_exercise.py , és adja hozzá a következő kódot:

    def admin_command(command, sudo=True):
        """
        Prefix a command with `sudo` unless it is explicitly not needed. Expects
        `command` to be a list.
        """
        if sudo:
            ["sudo"] + command
        return command
    

    A függvény admin_command() egy listát vesz fel bemenetként az command argumentum használatával, és opcionálisan előtagot sudois adhat a listának. Ha a sudo kulcsszóargumentum értéke be van állítva False, akkor ugyanazt a parancsot adja vissza, mint a bemenet.

  2. Ugyanebben a fájlban fűzze hozzá a függvény tesztjeit admin_command() . A tesztek egy segédmetódust használnak, amely egy mintaparancsot ad vissza:

    class TestAdminCommand:
    
    def command(self):
        return ["ps", "aux"]
    
    def test_no_sudo(self):
        result = admin_command(self.command(), sudo=False)
        assert result == self.command()
    
    def test_sudo(self):
        result = admin_command(self.command(), sudo=True)
        expected = ["sudo"] + self.command()
        assert result == expected
    

Feljegyzés

Nem gyakori, hogy a tesztek ugyanabban a fájlban vannak, mint a tényleges kód. Az egyszerűség kedvéért az ebben a gyakorlatban szereplő példák tényleges kóddal rendelkeznek ugyanabban a fájlban. A valós Python-projektekben a teszteket általában fájlok és könyvtárak választják el a tesztelt kódtól.

2. lépés – A tesztek futtatása és a hiba azonosítása

Most, hogy a tesztfájl rendelkezik egy tesztelendő függvénnyel és néhány teszttel a viselkedésének ellenőrzéséhez, ideje futtatni a teszteket, és hibákkal dolgozni.

  • Hajtsa végre a fájlt a Pythonnal:

    $ pytest test_exercise.py
    

    A futtatásnak egy teszttel és egy hibával kell befejeződnie, a hiba kimenetének pedig az alábbi kimenethez hasonlónak kell lennie:

    =================================== FAILURES ===================================
    __________________________ TestAdminCommand.test_sudo __________________________
    
    self = <test_exercise.TestAdminCommand object at 0x10634c2e0>
    
        def test_sudo(self):
            result = admin_command(self.command(), sudo=True)
            expected = ["sudo"] + self.command()
    >       assert result == expected
    E       AssertionError: assert ['ps', 'aux'] == ['sudo', 'ps', 'aux']
    E         At index 0 diff: 'ps' != 'sudo'
    E         Right contains one more item: 'aux'
    E         Use -v to get the full diff
    
    test_exercise.py:24: AssertionError
    =========================== short test summary info ============================
    FAILED test_exercise.py::TestAdminCommand::test_sudo - AssertionError: assert...
    ========================= 1 failed, 1 passed in 0.04s ==========================
    

    A kimenet sikertelen a test_sudo() teszten. A Pytest részletesen ismerteti az összehasonlítandó két listát. Ebben az esetben a result változóban nincs meg a sudo parancs, amit a teszt elvár.

3. lépés – A hiba kijavítása és a tesztek sikeressé tétele

Mielőtt bármilyen módosítást végez, először meg kell értenie, hogy miért van hiba. Bár láthatja, hogy a várakozás nem teljesül (sudo nem az eredmény), meg kell tudnia, hogy miért.

A feltétel teljesülése esetén admin_command() tekintse meg a sudo=True függvény következő kódsorait:

    if sudo:
        ["sudo"] + command

A listák művelete nem az érték visszaadására szolgál. Mivel a függvény nem adja vissza, a függvény a parancsot sudo nem mindig adja vissza.

  1. Frissítse a függvényt admin_command() a listaművelet visszaadásához, hogy a rendszer a módosított eredményt használja egy sudo parancs kérésekor. A frissített függvénynek így kell kinéznie:

    def admin_command(command, sudo=True):
        """
        Prefix a command with `sudo` unless it is explicitly not needed. Expects
        `command` to be a list.
        """
        if sudo:
            return ["sudo"] + command
        return command
    
  2. Futtassa újra a tesztet a Pytesttel. Próbálja meg növelni a kimenet részletességét a -v Pytest jelölőjével:

    $ pytest -v test_exercise.py
    
  3. Most ellenőrizze a kimenetet. Most két sikeres tesztet kell mutatnia:

    ============================= test session starts ==============================
    Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 
    cachedir: .pytest_cache
    rootdir: /private
    collected 2 items
    
    test_exercise.py::TestAdminCommand::test_no_sudo PASSED                  [ 50%]
    test_exercise.py::TestAdminCommand::test_sudo PASSED                     [100%]
    
    ============================== 2 passed in 0.00s ===============================
    

Feljegyzés

Mivel a függvény több különböző burkolatú értékkel is képes dolgozni, további tesztekkel kell kiegészíteni ezeket a változatokat. Ez megakadályozhatja, hogy a függvény jövőbeli módosításai eltérő (váratlan) viselkedést okozzanak.

4. lépés – Új kód hozzáadása tesztekkel

Miután hozzáadta a teszteket az előző lépésekben, nyugodtan módosíthatja a függvényt, és tesztekkel ellenőrizheti őket. Még ha a meglévő tesztek nem is fedik le a módosításokat, biztos lehet abban, hogy nem szakítja meg a korábbi feltételezéseket.

Ebben az esetben a admin_command() függvény vakon bízik abban, hogy az command argumentum mindig lista. Ezt úgy javíthatjuk, hogy egy hasznos hibaüzenettel rendelkező kivételt emelünk ki.

  1. Először hozzon létre egy tesztet, amely rögzíti a viselkedést. Bár a függvény még nem frissül, próbálkozzon egy első tesztalapú megközelítéssel (más néven tesztalapú fejlesztéssel vagy TDD-vel).

    • Frissítse a test_exercise.py fájlt úgy, hogy felülről importálja pytest . Ez a teszt egy belső segítőt használ a pytest keretrendszerből:
    import pytest
    
    • Most fűzjön hozzá egy új tesztet az osztályhoz a kivétel ellenőrzéséhez. Ennek a tesztnek a függvénytől kell várnia, TypeError ha az átadott érték nem lista:
        def test_non_list_commands(self):
            with pytest.raises(TypeError):
                admin_command("some command", sudo=True)
    
  2. Futtassa újra a teszteket a Pytest használatával. Mindannyiuknak át kell mennie.

    ============================= test session starts ==============================
    Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: /private/
    collected 3 items
    
    test_exercise.py ...                                                     [100%]
    
    ============================== 3 passed in 0.00s ===============================
    

    A teszt elég jó ahhoz, hogy ellenőrizze TypeError , de jó lenne hozzáadni a kódot egy hasznos hibaüzenettel.

  3. Frissítse a függvényt TypeError , hogy egy hasznos hibaüzenettel explicit módon emelje fel a függvényt:

    def admin_command(command, sudo=True):
        """
        Prefix a command with `sudo` unless it is explicitly not needed. Expects
        `command` to be a list.
        """
        if not isinstance(command, list):
            raise TypeError(f"was expecting command to be a list, but got a {type(command)}")
        if sudo:
            return ["sudo"] + command
        return command
    
  4. Végül frissítse a metódust a test_non_list_commands() hibaüzenet ellenőrzéséhez:

    def test_non_list_commands(self):
        with pytest.raises(TypeError) as error:
            admin_command("some command", sudo=True)
        assert error.value.args[0] == "was expecting command to be a list, but got a <class 'str'>"
    

    A frissített teszt változóként használja error az összes kivételinformációt. A használatával error.value.argsmegvizsgálhatja a kivétel argumentumait. Ebben az esetben az első argumentum a teszt által ellenőrizhető hibasztringgel rendelkezik.

Ellenőrizze munkáját

Ekkor rendelkeznie kell egy Python-tesztfájllal test_exercise.py , amely a következőket tartalmazza:

  • Argumentumot admin_command() és kulcsszóargumentumot elfogadó függvény.
  • Kivétel TypeError egy hasznos hibaüzenettel a admin_command() függvényben.
  • Egy TestAdminCommand() tesztosztály, amely egy command() segédmetódussal és három, a függvényt ellenőrző tesztmetódussal rendelkezik admin_command() .

A terminálon való futtatáskor az összes tesztnek hiba nélkül kell átesnie.