En introduktion til enhedstest i Python

Du er lige færdig med at skrive et stykke kode, og du spekulerer på, hvad du skal gøre. Vil du indsende en pull-anmodning og få dine holdkammerater til at gennemgå koden? Eller vil du teste koden manuelt?

Du skal gøre begge disse ting, men med et yderligere trin: du skal enhedsteste din kode for at sikre, at koden fungerer som beregnet.

Enhedstest kan bestå eller mislykkes, og det gør dem til en god teknik til at kontrollere din kode. I denne vejledning vil jeg demonstrere, hvordan man skriver enhedstest i Python, og du vil se, hvor let det er at få dem i gang i dit eget projekt.

Kom godt i gang

Den bedste måde, du kan forstå test på, er, hvis du gør det praktisk. Til dette formål vil jeg i en fil med navnet name_function.py skrive en simpel funktion, der tager et for- og efternavn og returnerer et fuldt navn:

#Generate a formatted full name def formatted_name(first_name, last_name): full_name = first_name + ' ' + last_name return full_name.title()

Funktionen formatted_name () tager for- og efternavnet og kombinerer dem med et mellemrum mellem for at danne et fuldt navn. Derefter kapitaliseres det første bogstav i hvert ord. For at kontrollere, at denne kode fungerer, skal du skrive en kode, der bruger denne funktion. I names.py vil jeg skrive nogle enkle koder, der lader brugerne indtaste deres for- og efternavne:

from name_function import formatted_name print("Please enter the first and last names or enter x to E[x]it.") while True: first_name = input("Please enter the first name: ") if first_name == "x": print("Good bye.") break last_name = input("Please enter the last name: ") if last_name == "x": print("Good bye.") break result = formatted_name(first_name, last_name) print("Formatted name is: " + result + ".")

Denne kode importerer formatted_name () fra name_function.py og kører, giver brugeren mulighed for at indtaste en række for- og efternavne og viser de formaterede fulde navne.

Enhedstest og testsager

Der er et modul i Pythons standardbibliotek kaldet unittest, der indeholder værktøjer til test af din kode. Enhedstest kontrollerer, om alle specifikke dele af din funktions opførsel er korrekte, hvilket gør det meget lettere at integrere dem sammen med andre dele.

Test case er en samling af enhedstest, der tilsammen beviser, at en funktion fungerer som beregnet, inden for en hel række situationer, hvor den funktion kan befinde sig, og som den forventes at håndtere. Test case skal overveje alle mulige typer input, som en funktion kan modtage fra brugerne, og bør derfor omfatte tests, der repræsenterer hver af disse situationer.

Bestå en test

Her er et typisk scenario til skrivning af prøver:

Først skal du oprette en testfil. Importér derefter det unittest-modul, definer testklassen, der arver fra unittest.TestCase, og til sidst skriv en række metoder til at teste alle tilfælde af din funktions adfærd.

Der er en linje for linje forklaring under følgende kode:

import unittest from name_function import formatted_name class NamesTestCase(unittest.TestCase): def test_first_last_name(self): result = formatted_name("pete", "seeger") self.assertEqual(result, "Pete Seeger")

Først skal du importere en unittest og den funktion, du vil teste, formatted_name (). Derefter opretter du en klasse, for eksempel NamesTestCase, der indeholder tests til din formatted_name () -funktion. Denne klasse arver fra klassen unittest.TestCase.

NamesTestCase indeholder en enkelt metode, der tester en del af formatted_name (). Du kan kalde denne metode test_first_last_name ().

Husk, at hver metode, der starter med "test_", køres automatisk, når du kører test_name_function.py.

Inden testmetoden test_first_last_name () kalder du den funktion, du vil teste, og gemmer en returværdi. I dette eksempel kalder vi formatted_name () med argumenterne "pete" og "seeger" og gemmer resultatet i den resulterende variabel.

I den sidste linje bruger vi assert-metoden. Assert-metoden verificerer, at et resultat, du har modtaget, matcher det resultat, du forventede at modtage. Og i dette tilfælde ved vi, at formatted_name () -funktionen returnerer fuldt navn med store bogstaver, så vi forventer resultatet "Pete Seeger". For at kontrollere dette bruges den unittests assertEqual () metode.

self.assertEqual(result, “Pete Seeger”)

Denne linje betyder dybest set: Sammenlign værdien i den resulterende variabel med “Pete Seeger”, og hvis de er ens, er det OK, men hvis de ikke får det til mig.

Når du kører test_name_function.py forventes det, at du får en OK, hvilket betyder, at testen er bestået.

Ran 1 test in 0.001s OK

Manglende test

For at vise dig, hvordan en svigtende test ser ud, skal jeg ændre en formatted_name () funktion ved at inkludere et nyt mellemnavn argument.

Så jeg vil omskrive funktionen for at se sådan ud:

#Generate a formatted full name including a middle name def formatted_name(first_name, last_name, middle_name): full_name = first_name + ' ' + middle_name + ' ' + last_name return full_name.title()

Denne version af formatted_name () fungerer for folk med mellemnavne, men når du tester det, vil du se, at funktionen er brudt for folk, der ikke har et mellemnavn.

Så når du kører test_name_function.py får du det output, der ser sådan ud:

Error Traceback (most recent call last): File “test_name_function.py”, line 7, in test_first_last_name result = formatted_name(“pete”, “seeger”) TypeError: formatted_name() missing 1 required positional argument: ‘middle_name’ Ran 1 test in 0.002s FAILED (errors=1)

I output vil du se oplysninger, der fortæller dig alt hvad du behøver for at vide, hvor testen mislykkes:

  • Første element i output er fejlen, der fortæller dig, at mindst en test i testsagen resulterede i en fejl.
  • Derefter ser du filen og metoden, hvor fejlen opstod.
  • Derefter vil du se den linje, hvor fejlen opstod.
  • Og hvilken slags fejl det er, i dette tilfælde mangler vi 1 argument "mellemnavn".
  • Du vil også se antallet af kørselstest, den tid, der er nødvendigt for testene at gennemføre, og en tekstbesked, der repræsenterer status for testene med antallet af fejl, der opstod.

Hvad skal jeg gøre, når testen mislykkes

En bestået test betyder, at funktionen opfører sig i henhold til, hvad der forventes af den. En svigtende test betyder imidlertid, at der er mere sjov foran dig.

Jeg har set et par programmerere, der foretrækker at ændre testen i stedet for at forbedre koden - men ikke til det. Brug lidt mere tid på at løse problemet, da det hjælper dig med bedre at forstå koden og spare tid på lang sigt.

In this example, our function formatted_name() first required two  parameters, and now as it is rewritten it requires one extra: a middle name. Adding a middle name to our function broke the desired behavior of  it. Since the idea is not to make changes to the tests, the best solution is to make middle name optional.

After we do this the idea is to make the tests pass when the first and last name are used, for example “Pete Seeger”, as well as when first, last and middle names are used, for example “Raymond Red Reddington”. So  let’s modify the code of formatted_name() once again:

#Generate a formatted full name including a middle name def formatted_name(first_name, last_name,): if len(middle_name) > 0: full_name = first_name + ' ' + middle_name + ' ' + last_name else: full_name = first_name + ' ' + last_name return full_name.title()

Now the function should work for names with and without the middle name.

And to make sure it still works with “Pete Seeger” run the test again:

Ran 1 test in 0.001s OK
Og det er det, jeg har tænkt mig at vise dig: Det er altid bedre at foretage ændringer i din kode, så den passer til dine tests end på anden måde. Nu er tiden inde til at tilføje en ny test for navne, der har et mellemnavn.

Tilføjelse af nye tests

Skriv en ny metode til NamesTestCase-klassen, der vil teste for mellemnavne:

import unittest from name_function import formatted_name class NamesTestCase(unittest.TestCase): def test_first_last_name(self): result = formatted_name("pete", "seeger") self.assertEqual(result, "Pete Seeger") def test_first_last_middle_name(self): result = formatted_name("raymond", "reddington", "red") self.assertEqual(result, "Raymond Red Reddington")

Når du har kørt testen, skal begge test bestå:

Ran 2 tests in 0.001s OK
Bra gjort!

Godt klaret!

Du har skrevet dine test for at kontrollere, om funktionen fungerer ved hjælp af navne med eller uden et mellemnavn. Hold øje med del 2, hvor jeg vil tale mere om test i Python.

Tak fordi du læste! Tjek flere artikler som denne på min freeCodeCamp-profil: //www.freecodecamp.org/news/author/goran/ og andre sjove ting, jeg bygger på min GitHub-side: //github.com/GoranAviani