Øvelse

Fuldført

I denne øvelse skal du bruge pytest med parametrize til at teste en funktion. Derefter skal du opdatere en testklasse for at bruge en armatur i stedet for en setup() og teardown() metode. Brug parametrize og arbejde med armaturer giver dig mulighed for at blive mere fleksibel, når du opretter eller opdaterer test.

Trin 1 – Tilføj en fil med test til denne øvelse

  1. Opret en ny testfil med navnet test_advanced.py, og tilføj følgende kode:

    def str_to_bool(string):
        if string.lower() in ['yes', 'y', '1']:
            return True
        elif string.lower() in ['no', 'n', '0']:
            return False
    
    

    Funktionen str_to_bool() accepterer en streng som input, og afhængigt af dens indhold returnerer den en True eller False værdi.

  2. Tilføj testene for funktionen str_to_bool() i den samme fil. Brug pytest.mark.parametrize() til først at teste alle de sande værdier:

    import pytest 
    
    @pytest.mark.parametrize("string", ['Y', 'y', '1', 'YES'])
    def test_str_to_bool_true(string):
        assert str_to_bool(string) is True
    
  3. Derefter skal du tilføje en anden test med de falske værdier:

    @pytest.mark.parametrize("string", ['N', 'n', '0', 'NO'])
    def test_str_to_bool_false(string):
        assert str_to_bool(string) is False
    

    Der er nu to test, der dækker alle mulige input for både True og False returværdier.

Seddel

Det er ikke almindeligt at have test i den samme fil som den faktiske kode. For nemheds skyld vil eksemplerne i denne øvelse have den faktiske kode i den samme fil. I pythonprojekter i den virkelige verden kan du se, at test er adskilt af filer og mapper fra den kode, der testes.

Trin 2 – Kør testene, og udforsk rapporten

Når du har tilføjet testene, er det næste trin at køre pytest og undersøge outputtet. Brug flaget for øget verbositet (-v), så du kan se, at alle inputværdier behandles som en separat test.

$ pytest -v test_avanced.py
============================= test session starts ==============================
Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 
rootdir: /private
collected 8 items

test_advanced.py::test_str_to_bool_true[Y] PASSED                        [ 12%]
test_advanced.py::test_str_to_bool_true[y] PASSED                        [ 25%]
test_advanced.py::test_str_to_bool_true[1] PASSED                        [ 37%]
test_advanced.py::test_str_to_bool_true[YES] PASSED                      [ 50%]
test_advanced.py::test_str_to_bool_false[N] PASSED                       [ 62%]
test_advanced.py::test_str_to_bool_false[n] PASSED                       [ 75%]
test_advanced.py::test_str_to_bool_false[0] PASSED                       [ 87%]
test_advanced.py::test_str_to_bool_false[NO] PASSED                      [100%]

============================== 8 passed in 0.01s ===============================

Selvom du kun skrev to testfunktioner, kunne pytest oprette otte test i alt takket være funktionen parametrize().

Trin 3 – Portér en eksisterende test til et fast punkt

  1. Føj en ny klassebaseret test til filen test_advanced.py. Denne test skal bruge en setup() og teardown() funktion, der opretter en midlertidig fil med noget tekst på den. Efter hver test fjernes filen. Det skal se sådan ud:

    import os
    
    
    class TestFile:
    
        def setup(self):
            with open("/tmp/done", 'w') as _f:
                _f.write("1")
    
        def teardown(self):
            try:
                os.remove("/tmp/done")
            except OSError:
                pass
    
        def test_done_file(self):
            with open("/tmp/done") as _f:
                contents = _f.read()
            assert contents == "1"
    

    Denne testklasse opretter en fil, men er problematisk, fordi stien til /tmp/ ikke garanteres at være til stede på alle systemer.

  2. Opret en armatur, der bruger pytesttmpdir() armatur til at skrive til filen og returnere stien:

    import pytest
    
    @pytest.fixture
    def tmpfile(tmpdir):
        def write():
            file = tmpdir.join("done")
            file.write("1")
            return file.strpath
        return write
    

    Den tmpfile() armatur bruger pytest's tmpdir() armatur, som garanterer en gyldig midlertidig fil, der bliver renset efter test er færdig.

  3. Opdater klassen TestFile, så den bruger i stedet for at hjælpemetoderne:

    class TestFile:
    
        def test_f(self, tmpfile):
            path = tmpfile()
            with open(path) as _f:
                contents = _f.read()
            assert contents == "1"
    

    Denne testklasse kan nu sikre, at der oprettes en midlertidig fil, og at den har det korrekte indhold, så antagelsen kan fungere.

Kontrollér dit arbejde

Nu skal du have en Python-fil med navnet test_advanced.py med følgende kode:

  • En str_to_bool() funktion, der accepterer en streng og returnerer en boolesk værdi, afhængigt af indholdet af strengen.
  • To parametriserede test for funktionen str_to_bool(), én, der tester de True værdier, og den anden, der tester de False værdier.
  • En brugerdefineret pytest armatur, der bruger tmpdir()-armaturet til at oprette en midlertidig udført fil med noget indhold.
  • En testklasse, der bruger den brugerdefinerede tmpfile() fastgørelse til at oprette filen.

Alle test skal bestå, når de køres i terminalen uden fejl.