En introduktion till enhetstestning i Python

Du har precis skrivit en bit kod och du undrar vad du ska göra. Kommer du att skicka in en begäran om dragning och få dina lagkamrater att granska koden? Eller kommer du att testa koden manuellt?

Du bör göra båda dessa saker, men med ett ytterligare steg: du måste testa din kod för att se till att koden fungerar som avsett.

Enhetstester kan klara eller misslyckas, och det gör dem till en bra teknik för att kontrollera din kod. I den här handledningen kommer jag att demonstrera hur man skriver enhetstester i Python och du kommer att se hur lätt det är att få dem att gå i ditt eget projekt.

Komma igång

Det bästa sättet du kan förstå testning är om du gör det praktiskt. För det ändamålet, i en fil som heter name_function.py, kommer jag att skriva en enkel funktion som tar ett för- och efternamn och returnerar ett fullständigt namn:

#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 () tar för- och efternamnet och kombinerar dem med ett mellanslag mellan för att bilda ett fullständigt namn. Det bokstäver sedan den första bokstaven i varje ord. För att kontrollera att den här koden fungerar måste du skriva en kod som använder den här funktionen. I names.py kommer jag att skriva en enkel kod som låter användare ange sina för- och efternamn:

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 + ".")

Den här koden importerar formatted_name () från name_function.py och körs, tillåter användaren att ange en serie för- och efternamn och visar de formaterade fullständiga namnen.

Enhetstest och testfall

Det finns en modul i Pythons standardbibliotek som heter unittest som innehåller verktyg för att testa din kod. Enhetstestning kontrollerar om alla specifika delar av din funktions beteende är korrekta, vilket gör det mycket enklare att integrera dem med andra delar.

Testfall är en samling enhetstester som tillsammans bevisar att en funktion fungerar som avsett, inom en rad olika situationer där den funktionen kan befinna sig och att den förväntas hantera. Testfallet bör överväga alla möjliga typer av inmatningar som en funktion kan få från användare och bör därför innehålla tester som representerar var och en av dessa situationer.

Klarar ett test

Här är ett typiskt scenario för att skriva tester:

Först måste du skapa en testfil. Importera sedan unittest-modulen, definiera testklassen som ärver från unittest.TestCase, och slutligen, skriv en serie metoder för att testa alla fall av din funktions beteende.

Det finns en rad för rad-förklaring nedanför följande kod:

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 måste du importera en unittest och den funktion du vill testa, formatted_name (). Sedan skapar du en klass, till exempel NamesTestCase, som innehåller test för din formatted_name () -funktion. Denna klass ärver från klassen unittest.TestCase.

NamesTestCase innehåller en enda metod som testar en del av formatted_name (). Du kan anropa den här metoden test_first_last_name ().

Kom ihåg att varje metod som börjar med "test_" körs automatiskt när du kör test_name_function.py.

Inom testmetoden test_first_last_name () anropar du den funktion du vill testa och lagrar ett returvärde. I det här exemplet ska vi anropa formatted_name () med argumenten “pete” och “seeger” och lagra resultatet i den resulterande variabeln.

I den sista raden kommer vi att använda assertmetoden. Assertmetoden verifierar att ett resultat du fick matchar det resultat du förväntade dig att få. Och i det här fallet vet vi att funktionen formatted_name () kommer att returnera fullt namn med stora bokstäver, så vi förväntar oss resultatet "Pete Seeger". För att kontrollera detta används unittest's assertEqual () -metod.

self.assertEqual(result, “Pete Seeger”)

Den här raden betyder i princip: Jämför värdet i den resulterande variabeln med “Pete Seeger” och om de är lika är det OK, men om de inte får veta det.

När du kör test_name_function.py förväntas du få en OK, vilket innebär att testet har passerat.

Ran 1 test in 0.001s OK

Misslyckas ett test

För att visa hur ett misslyckande test ser ut ska jag ändra en formatted_name () -funktion genom att inkludera ett nytt mellannamnsargument.

Så jag ska skriva om funktionen så att den ser ut så här:

#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()

Denna version av formatted_name () fungerar för personer med mellannamn, men när du testar det ser du att funktionen är trasig för personer som inte har ett mellannamn.

Så när du kör test_name_function.py får du utdata som ser ut så här:

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 utgången ser du information som berättar allt du behöver för att veta var testet misslyckas:

  • Det första objektet i utgången är Fel som berättar att minst ett test i testfallet resulterade i ett fel.
  • Därefter ser du filen och metoden där felet uppstod.
  • Därefter ser du raden där felet inträffade.
  • Och vilken typ av fel det är, i det här fallet saknar vi 1 argument "mellannamn".
  • Du kommer också att se antalet körtester, den tid som krävs för att testerna ska slutföras och ett textmeddelande som representerar testens status med antalet fel som inträffat.

Vad ska jag göra när testet har misslyckats

Ett godkänt test innebär att funktionen beter sig enligt vad som förväntas av den. Ett misslyckande test innebär dock att det finns roligare framför dig.

Jag har sett några programmerare som föredrar att ändra testet istället för att förbättra koden - men gör inte det. Tillbringa lite mer tid för att åtgärda problemet, eftersom det hjälper dig att bättre förstå koden och spara tid på lång sikt.

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
Och det här är vad jag tänkte visa dig: Det är alltid bättre att göra ändringar i din kod för att passa dina tester än tvärtom. Nu är det dags att lägga till ett nytt test för namn som har ett mellannamn.

Lägga till nya tester

Skriv en ny metod till klassen NamesTestCase som testar för mellannamn:

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 testet ska båda testerna klara:

Ran 2 tests in 0.001s OK
Bra gjort!

Bra gjort!

Du har skrivit dina tester för att kontrollera om funktionen fungerar med namn med eller utan mellannamn. Håll ögonen öppna för del 2 där jag ska prata mer om testning i Python.

Tack för att du läste! Kolla in fler artiklar så här på min freeCodeCamp-profil: //www.freecodecamp.org/news/author/goran/ och andra roliga saker jag bygger på min GitHub-sida: //github.com/GoranAviani