doctest — Testa interaktiva Python-exempel

Källkod: Lib/doctest.py


Modulen doctest söker efter textstycken som ser ut som interaktiva Python-sessioner och kör sedan dessa sessioner för att verifiera att de fungerar exakt som de visas. Det finns flera vanliga sätt att använda doctest:

  • För att kontrollera att en moduls dokumentation är uppdaterad genom att verifiera att alla interaktiva exempel fortfarande fungerar enligt dokumentationen.

  • Att utföra regressionstest genom att verifiera att interaktiva exempel från en testfil eller ett testobjekt fungerar som förväntat.

  • Att skriva handledningsdokumentation för ett paket, rikligt illustrerad med exempel på inmatning och utmatning. Beroende på om exemplen eller den förklarande texten betonas, har detta en smak av ”litterat testande” eller ”körbar dokumentation”.

Här är en komplett men liten exempelmodul:

"""
This is the "example" module.

The example module supplies one function, factorial().  For example,

>>> factorial(5)
120
"""

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(30)
    265252859812191058636308480000000
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    >>> factorial(30.1)
    Traceback (most recent call last):
        ...
    ValueError: n must be exact integer
    >>> factorial(30.0)
    265252859812191058636308480000000

    It must also not be ridiculously large:
    >>> factorial(1e100)
    Traceback (most recent call last):
        ...
    OverflowError: n too large
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result


if __name__ == "__main__":
    import doctest
    doctest.testmod()

Om du kör example.py direkt från kommandoraden, kommer doctest att utföra sin magi:

$ python example.py
$

Det finns ingen utdata! Det är normalt, och det betyder att alla exempel fungerade. Skicka -v till skriptet, och doctest skriver ut en detaljerad logg över vad det försöker göra, och skriver ut en sammanfattning i slutet:

$ python example.py -v
Trying:
    factorial(5)
Expecting:
    120
ok
Trying:
    [factorial(n) for n in range(6)]
Expecting:
    [1, 1, 2, 6, 24, 120]
ok

Och så vidare, för att slutligen sluta med:

Trying:
    factorial(1e100)
Expecting:
    Traceback (most recent call last):
        ...
    OverflowError: n too large
ok
2 items passed all tests:
   1 test in __main__
   6 tests in __main__.factorial
7 tests in 2 items.
7 passed.
Test passed.
$

Det är allt du behöver veta för att börja använda doctest på ett produktivt sätt! Hoppa in. Följande avsnitt ger fullständiga detaljer. Observera att det finns många exempel på doctests i Pythons standardtestsvit och bibliotek. Speciellt användbara exempel finns i standardtestfilen Lib/test/test_doctest/test_doctest.py.

Tillagd i version 3.13: Utdata är färgade som standard och kan kontrolleras med hjälp av miljövariabler.

Enkel användning: Kontrollera exempel i dokumentsträngar

Det enklaste sättet att börja använda doctest (men inte nödvändigtvis det sätt som du kommer att fortsätta att göra det på) är att avsluta varje modul M med:

if __name__ == "__main__":
    import doctest
    doctest.testmod()

doctest undersöker sedan dokumentsträngar i modulen M.

Om modulen körs som ett skript kommer exemplen i dokumentationen att köras och verifieras:

python M.py

Detta kommer inte att visa någonting om inte ett exempel misslyckas, i vilket fall de misslyckade exemplen och orsaken till misslyckandet skrivs ut till stdout, och den sista utdataraden är ***Test Failed*** N failures., där N är antalet exempel som misslyckades.

Kör det med -v-omkopplaren istället:

python M.py -v

och en detaljerad rapport om alla exempel som provats skrivs ut till standardutmatningen, tillsammans med diverse sammanfattningar i slutet.

Du kan tvinga fram verbose-läge genom att skicka verbose=True till testmod(), eller förbjuda det genom att skicka verbose=False. I något av dessa fall undersöks inte sys.argv av testmod() (så att skicka -v eller inte har ingen effekt).

Det finns också en kommandoradsgenväg för att köra testmod(), se avsnitt Användning på kommandoraden.

För mer information om testmod(), se avsnitt Grundläggande API.

Enkel användning: Kontrollera exempel i en textfil

En annan enkel tillämpning av doctest är att testa interaktiva exempel i en textfil. Detta kan göras med funktionen testfile():

import doctest
doctest.testfile("exempel.txt")

Det korta skriptet exekverar och verifierar alla interaktiva Python-exempel som finns i filen example.txt. Filens innehåll behandlas som om det vore en enda stor dokumentsträng; filen behöver inte innehålla ett Python-program! Till exempel kanske example.txt innehåller detta:

The ``example`` module
======================

Using ``factorial``
-------------------

This is an example text file in reStructuredText format.  First import
``factorial`` from the ``example`` module:

    >>> from example import factorial

Now use it:

    >>> factorial(6)
    120

När man kör doctest.testfile("example.txt") hittar man sedan felet i denna dokumentation:

File "./example.txt", line 14, in example.txt
Failed example:
    factorial(6)
Expected:
    120
Got:
    720

Precis som med testmod() kommer testfile() inte att visa något om inte ett exempel misslyckas. Om ett exempel misslyckas, skrivs det eller de misslyckade exemplen och orsaken till misslyckandet ut till stdout, i samma format som testmod().

Som standard letar testfile() efter filer i den anropande modulens katalog. Se avsnitt Grundläggande API för en beskrivning av de valfria argument som kan användas för att be den leta efter filer på andra platser.

I likhet med testmod() kan testfile():s ordrikedom ställas in med kommandoradskommandot -v eller med det valfria nyckelordsargumentet verbose.

Det finns också en kommandoradsgenväg för att köra testfile(), se avsnitt Användning på kommandoraden.

För mer information om testfile(), se avsnitt Grundläggande API.

Användning på kommandoraden

Modulen doctest kan startas som ett skript från kommandoraden:

python -m doctest [-v] [-o OPTION] [-f] file [file ...]
-v, --verbose

En detaljerad rapport över alla exempel som testats skrivs ut till standardutdata, tillsammans med diverse sammanfattningar i slutet:

python -m doctest -v example.py

Detta kommer att importera example.py som en fristående modul och köra testmod() på den. Observera att det här kanske inte fungerar korrekt om filen är en del av ett paket och importerar andra undermoduler från det paketet.

Om filnamnet inte slutar med .py, drar doctest slutsatsen att den måste köras med testfile() istället:

python -m doctest -v example.txt
-o, --option <option>

Optionsflaggor styr olika aspekter av doctests beteende, se avsnitt Flaggor för alternativ.

Tillagd i version 3.4.

-f, --fail-fast

Detta är en förkortning för -o FAIL_FAST.

Tillagd i version 3.4.

Hur det fungerar

I det här avsnittet undersöks i detalj hur doctest fungerar: vilka dokumentsträngar det tittar på, hur det hittar interaktiva exempel, vilket exekveringskontext det använder, hur det hanterar undantag och hur alternativflaggor kan användas för att styra dess beteende. Detta är den information som du behöver för att skriva doctest-exempel; för information om hur du faktiskt kör doctest på dessa exempel, se följande avsnitt.

Vilka dokumentsträngar granskas?

Modulens dokumentsträng och alla funktions-, klass- och metoddokumentsträngar genomsöks. Objekt som importeras till modulen genomsöks inte.

Dessutom finns det fall där du vill att tester ska vara en del av en modul men inte en del av hjälptexten, vilket kräver att testerna inte ingår i dokumentsträngen. Doctest letar efter en variabel på modulnivå som heter __test__ och använder den för att hitta andra tester. Om M.__test__ finns måste den vara en dict, och varje post mappar ett (sträng)namn till ett funktionsobjekt, klassobjekt eller en sträng. Dokumentsträngar för funktions- och klassobjekt som hittas från M.__test__ söks igenom och strängar behandlas som om de vore dokumentsträngar. I utdata visas en nyckel K i M.__test__ med namnet M.__test__.K.

Placera till exempel det här kodblocket högst upp i example.py:

__test__ = {
    'numbers': """
>>> factorial(6)
720

>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
"""
}

Värdet av example.__test__["numbers"] kommer att behandlas som en docstring och alla tester i den kommer att köras. Det är viktigt att notera att värdet kan mappas till en funktion, ett klassobjekt eller en modul; om så är fallet söker doctest igenom dem rekursivt efter docstrings, som sedan genomsöks efter tester.

Alla klasser som hittas genomsöks rekursivt på samma sätt för att testa dokumentsträngar i de metoder och nästlade klasser som ingår.

Anteckning

doctest kan endast automatiskt upptäcka klasser och funktioner som är definierade på modulnivå eller inuti andra klasser.

Eftersom kapslade klasser och funktioner endast existerar när en yttre funktion anropas, kan de inte upptäckas. Definiera dem utanför för att göra dem synliga.

Hur känns Docstring-exempel igen?

I de flesta fall fungerar en kopia och klistra in av en interaktiv konsolsession bra, men doctest försöker inte göra en exakt emulering av något specifikt Python-skal.

>>> # comments are ignored
>>> x = 12
>>> x
12
>>> if x == 13:
...     print("yes")
... else:
...     print("no")
...     print("NO")
...     print("NO!!!")
...
no
NO
NO!!!
>>>

Any expected output must immediately follow the final '>>> ' or '... ' line containing the code, and the expected output (if any) extends to the next '>>> ' or all-whitespace line.

Det finstilta:

  • Förväntad utdata kan inte innehålla en rad med enbart blanksteg, eftersom en sådan rad anses signalera slutet på förväntad utdata. Om förväntad utdata innehåller en blankrad, lägg till <BLANKLINE> i ditt doctest-exempel varje gång en blankrad förväntas.

  • Alla hårda tabbtecken expanderas till mellanslag med tabbstopp i 8 kolumner. Tabbar i utdata som genereras av den testade koden ändras inte. Eftersom alla hårda tabbar i exempelutmatningen expanderas innebär detta att om kodutmatningen innehåller hårda tabbar är det enda sättet för doctestet att bli godkänt om alternativet NORMALIZE_WHITESPACE eller directive är i kraft. Alternativt kan testet skrivas om för att fånga utdata och jämföra det med ett förväntat värde som en del av testet. Den här hanteringen av tabbar i källan har kommit till genom försök och misstag och har visat sig vara det minst felbenägna sättet att hantera dem. Det är möjligt att använda en annan algoritm för att hantera tabbar genom att skriva en egen DocTestParser-klass.

  • Utdata till stdout fångas upp, men inte utdata till stderr (spårningar av undantag fångas upp på ett annat sätt).

  • Om du fortsätter en rad med hjälp av backslash i en interaktiv session, eller av någon annan anledning använder backslash, bör du använda en rå docstring, som bevarar dina backslash exakt som du skriver dem:

    >>> def f(x):
    ...     r'''Backslashes in a raw docstring: m\n'''
    ...
    >>> print(f.__doc__)
    Backslashes in a raw docstring: m\n
    

    I annat fall tolkas backslash som en del av strängen. Till exempel skulle n ovan tolkas som ett tecken för ny rad. Alternativt kan du fördubbla varje backslash i doctest-versionen (och inte använda en rå sträng):

    >>> def f(x):
    ...     '''Backslashes in a raw docstring: m\\n'''
    ...
    >>> print(f.__doc__)
    Backslashes in a raw docstring: m\n
    
  • Startkolumnen spelar ingen roll:

    >>> assert "Easy!"
          >>> import math
              >>> math.floor(1.9)
              1
    

    and as many leading whitespace characters are stripped from the expected output as appeared in the initial '>>> ' line that started the example.

Vad är exekveringskontexten?

Som standard, varje gång doctest hittar en dokumentsträng att testa, använder den en grunt kopia av M:s globaler, så att körning av tester inte ändrar modulens verkliga globaler, och så att ett test i M inte kan lämna efter sig smulor som av misstag tillåter ett annat test att fungera. Detta innebär att exempel fritt kan använda alla namn som definieras på toppnivå i M, och namn som definieras tidigare i den dokumentsträng som körs. Exempel kan inte se namn som definierats i andra dokumentsträngar.

Du kan tvinga fram användning av din egen dict som exekveringskontext genom att skicka globs=your_dict till testmod() eller testfile() istället.

Hur är det med undantag?

Inga problem, förutsatt att spårningen är den enda utdata som exemplet ger: klistra bara in spårningen. [1] Eftersom spårningar innehåller detaljer som sannolikt kommer att ändras snabbt (till exempel exakta filsökvägar och radnummer) är detta ett fall där doctest arbetar hårt för att vara flexibel i vad den accepterar.

Ett enkelt exempel:

>>> [1, 2, 3].remove(42)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list

Detta doctest lyckas om ValueError tas upp, med list.remove(x): x not in list detalj som visas.

Den förväntade utdata för ett undantag måste börja med en spårningsrubrik, som kan vara någon av följande två rader, indragna på samma sätt som den första raden i exemplet:

Traceback (most recent call last):
Traceback (innermost last):

Traceback-huvudet följs av en valfri traceback-stack, vars innehåll ignoreras av doctest. Traceback-stacken utelämnas vanligtvis eller kopieras ordagrant från en interaktiv session.

Efter spårningsstacken följer den mest intressanta delen: raden/raderna som innehåller undantagstypen och detaljerna. Detta är vanligtvis den sista raden i en spårning, men kan sträcka sig över flera rader om undantaget har en detalj med flera rader:

>>> raise ValueError('multi\n    line\ndetail')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: multi
    line
detail

De tre sista raderna (som börjar med ValueError) jämförs med undantagets typ och detalj, och resten ignoreras.

Bästa praxis är att utelämna traceback-stacken, såvida den inte tillför ett betydande dokumentationsvärde till exemplet. Så det sista exemplet är förmodligen bättre som:

>>> raise ValueError('multi\n    line\ndetail')
Traceback (most recent call last):
    ...
ValueError: multi
    line
detail

Observera att spårningar behandlas mycket speciellt. I synnerhet i det omskrivna exemplet är användningen av ... oberoende av doctests ELLIPSIS-alternativ. Ellipsen i det exemplet kan utelämnas, eller lika gärna vara tre (eller trehundra) kommatecken eller siffror, eller en indragen utskrift av en Monty Python-sketch.

Vissa detaljer bör du läsa en gång, men behöver inte komma ihåg:

  • Doctest kan inte gissa om den förväntade utmatningen kommer från en exception traceback eller från vanlig utskrift. Så, t.ex., ett exempel som förväntar sig ValueError: 42 is prime kommer att godkännas oavsett om ValueError faktiskt uppstår eller om exemplet bara skriver ut den spårningstexten. I praktiken börjar vanliga utdata sällan med en spårningshuvudrad, så det här skapar inga verkliga problem.

  • Varje rad i spårningsstacken (om sådan finns) måste vara indragen längre än den första raden i exemplet, eller börja med ett icke-alfanumeriskt tecken. Den första raden efter spårningshuvudet som är indragen på samma sätt och som börjar med ett alfanumeriskt tecken anses vara början på undantagsdetaljen. Naturligtvis gör detta det rätta för äkta spårningar.

  • När doctest-alternativet IGNORE_EXCEPTION_DETAIL anges ignoreras allt som följer efter kolon längst till vänster och all modulinformation i undantagsnamnet.

  • Det interaktiva skalet utelämnar spårningshuvudraden för vissa SyntaxError. Men doctest använder spårningshuvudraden för att skilja undantag från icke-undantag. Så i det sällsynta fall då du behöver testa ett SyntaxError som utelämnar traceback-rubriken, måste du manuellt lägga till traceback-rubriken i ditt testexempel.

  • För vissa undantag visar Python felets position med hjälp av ^-markörer och tildes:

    >>> 1 + None
      File "<stdin>", line 1
        1 + None
        ~~^~~~~~
    TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
    

    Eftersom raderna som visar felets position kommer före undantagstypen och detaljerna, kontrolleras de inte av doctest. Till exempel skulle följande test godkännas, även om det placerar ^-markören på fel plats:

    >>> 1 + None
      File "<stdin>", line 1
        1 + None
        ^~~~~~~~
    TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
    

Flaggor för alternativ

Ett antal optionsflaggor styr olika aspekter av doctests beteende. Symboliska namn för flaggorna anges som modulkonstanter, som kan bitwise ORed ihop och skickas till olika funktioner. Namnen kan också användas i doctest-direktiv, och kan skickas till doctests kommandoradsgränssnitt via alternativet -o.

Den första gruppen av alternativ definierar testets semantik och styr aspekter av hur doctest avgör om den faktiska utdata stämmer överens med ett exempels förväntade utdata:

doctest.DONT_ACCEPT_TRUE_FOR_1

Som standard, om ett förväntat utdatablock innehåller bara 1, anses ett faktiskt utdatablock som innehåller bara 1 eller bara True vara en matchning, och på samma sätt för 0 kontra False. När DONT_ACCEPT_TRUE_FOR_1 anges tillåts ingen av dessa substitutioner. Standardbeteendet tar hänsyn till att Python ändrade returtypen för många funktioner från heltal till boolean; doctests som förväntar sig ”little integer”-utdata fungerar fortfarande i dessa fall. Detta alternativ kommer förmodligen att försvinna, men inte på flera år.

doctest.DONT_ACCEPT_BLANKLINE

Om ett förväntat utdatablock innehåller en rad som bara innehåller strängen <BLANKLINE>, kommer den raden som standard att matcha en tom rad i den faktiska utdatan. Eftersom en blank rad verkligen avgränsar den förväntade utdata, är detta det enda sättet att kommunicera att en blank rad förväntas. När DONT_ACCEPT_BLANKLINE anges är denna substitution inte tillåten.

doctest.NORMALIZE_WHITESPACE

När detta anges behandlas alla sekvenser av blanktecken (blanksteg och nya linjer) som lika. Alla sekvenser av blanksteg i den förväntade utskriften kommer att matcha alla sekvenser av blanksteg i den faktiska utskriften. Som standard måste blanksteg matcha exakt. NORMALIZE_WHITESPACE är särskilt användbart när en rad med förväntad utdata är mycket lång och du vill lägga den över flera rader i källan.

doctest.ELLIPSIS

När detta anges kan en ellipsmarkör (...) i den förväntade utdata matcha vilken delsträng som helst i den faktiska utdata. Detta inkluderar substrängar som sträcker sig över radgränser och tomma substrängar, så det är bäst att hålla användningen av detta enkel. Komplicerade användningar kan leda till samma typ av ”oops, det matchade för mycket!” överraskningar som .* är benägen att i reguljära uttryck.

doctest.IGNORE_EXCEPTION_DETAIL

När detta anges godkänns doctests som väntar på undantag så länge ett undantag av den förväntade typen uppstår, även om detaljerna (meddelande och fullständigt kvalificerat undantagsnamn) inte stämmer överens.

Till exempel kommer ett exempel som förväntar sig ValueError: 42 kommer att godkännas om det faktiska undantaget är ValueError: 3*14, men kommer att misslyckas om, säg, ett TypeError tas upp istället. Den kommer också att ignorera alla fullständigt kvalificerade namn som ingår före undantagsklassen, vilket kan variera mellan implementationer och versioner av Python och den kod / bibliotek som används. Därför kommer alla dessa tre variationer att fungera med den angivna flaggan:

>>> raise Exception('message')
Traceback (most recent call last):
Exception: message

>>> raise Exception('message')
Traceback (most recent call last):
builtins.Exception: message

>>> raise Exception('message')
Traceback (most recent call last):
__main__.Exception: message

Observera att ELLIPSIS också kan användas för att ignorera detaljerna i undantagsmeddelandet, men ett sådant test kan fortfarande misslyckas beroende på om modulnamnet finns eller matchar exakt.

Ändrad i version 3.2: IGNORE_EXCEPTION_DETAIL ignorerar nu även all information som rör den modul som innehåller det undantag som testas.

doctest.SKIP

Om detta anges ska exemplet inte köras alls. Detta kan vara användbart i sammanhang där doctest-exempel fungerar som både dokumentation och testfall, och ett exempel bör inkluderas för dokumentationsändamål, men inte bör kontrolleras. Exemplets utdata kan t.ex. vara slumpmässig, eller så kan exemplet vara beroende av resurser som inte är tillgängliga för testföraren.

SKIP-flaggan kan också användas för att tillfälligt ”kommentera bort” exempel.

doctest.COMPARISON_FLAGS

En bitmask som kombinerar alla jämförelseflaggorna ovan.

Den andra gruppen av alternativ styr hur testfel rapporteras:

doctest.REPORT_UDIFF

När så anges visas fel som omfattar förväntade och faktiska utdata på flera rader med en enhetlig diff.

doctest.REPORT_CDIFF

Om detta anges kommer fel som innehåller flera rader med förväntade och faktiska utdata att visas med hjälp av en kontextdiff.

doctest.REPORT_NDIFF

När detta anges beräknas skillnaderna av difflib.Differ, som använder samma algoritm som det populära verktyget ndiff.py. Detta är den enda metod som markerar skillnader inom rader såväl som mellan rader. Om t.ex. en rad med förväntad utmatning innehåller siffran 1 medan den faktiska utmatningen innehåller bokstaven l, infogas en rad med en caret som markerar de felaktiga kolumnpositionerna.

doctest.REPORT_ONLY_FIRST_FAILURE

När detta anges visas det första misslyckade exemplet i varje doctest, men utdata för alla återstående exempel undertrycks. Detta kommer att förhindra doctest från att rapportera korrekta exempel som misslyckas på grund av tidigare misslyckanden; men det kan också dölja felaktiga exempel som misslyckas oberoende av det första misslyckandet. När REPORT_ONLY_FIRST_FAILURE anges, körs de återstående exemplen fortfarande och räknas fortfarande in i det totala antalet fel som rapporteras; endast utdata undertrycks.

doctest.FAIL_FAST

När den anges avslutas programmet efter det första misslyckade exemplet och försöker inte köra de återstående exemplen. Antalet misslyckanden som rapporteras blir således högst 1. Denna flagga kan vara användbar under felsökning, eftersom exempel efter det första misslyckandet inte ens kommer att producera felsökningsutdata.

doctest.REPORTING_FLAGS

En bitmask som kombinerar alla rapporteringsflaggor ovan.

Det finns också ett sätt att registrera nya alternativflaggnamn, men detta är inte användbart om du inte tänker utöka doctest internals via underklassning:

doctest.register_optionflag(name)

Skapa en ny alternativflagga med ett givet namn och returnera den nya flaggans heltalsvärde. register_optionflag() kan användas när du underklassar OutputChecker eller DocTestRunner för att skapa nya alternativ som stöds av dina underklasser. register_optionflag() bör alltid anropas med följande idiom:

MY_FLAG = register_optionflag('MY_FLAG')

Direktiv

Doctest-direktiv kan användas för att ändra alternativflaggor för ett enskilt exempel. Doctest-direktiv är speciella Python-kommentarer som följer efter ett exempels källkod:

directive:             "#" "doctest:" directive_options
directive_options:     directive_option ("," directive_option)*
directive_option:      on_or_off directive_option_name
on_or_off:             "+" | "-"
directive_option_name: "DONT_ACCEPT_BLANKLINE" | "NORMALIZE_WHITESPACE" | ...

Whitespace är inte tillåtet mellan + eller - och namnet på direktivalternativet. Namnet på direktivalternativet kan vara vilket som helst av de flaggnamn för alternativ som förklaras ovan.

Ett exempels doctest-direktiv ändrar doctests beteende för det enskilda exemplet. Använd + för att aktivera det angivna beteendet, eller - för att inaktivera det.

Det här testet är till exempel godkänt:

>>> print(list(range(20)))  # doctest: +NORMALIZE_WHITESPACE
[0,   1,  2,  3,  4,  5,  6,  7,  8,  9,
10,  11, 12, 13, 14, 15, 16, 17, 18, 19]

Utan direktivet skulle det misslyckas, både för att den faktiska utmatningen inte har två blanksteg före de ensiffriga listelementen och för att den faktiska utmatningen är på en enda rad. Det här testet är också godkänt och kräver också ett direktiv för att bli det:

>>> print(list(range(20)))  # doctest: +ELLIPSIS
[0, 1, ..., 18, 19]

Flera direktiv kan användas på en och samma fysiska rad, åtskilda med kommatecken:

>>> print(list(range(20)))  # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
[0,    1, ...,   18,    19]

Om flera direktivkommentarer används för ett och samma exempel, kombineras de:

>>> print(list(range(20)))  # doctest: +ELLIPSIS
...                         # doctest: +NORMALIZE_WHITESPACE
[0,    1, ...,   18,    19]

Som det föregående exemplet visar kan du lägga till ... rader till ditt exempel som bara innehåller direktiv. Detta kan vara användbart när ett exempel är för långt för att ett direktiv ska rymmas på samma rad:

>>> print(list(range(5)) + list(range(10, 20)) + list(range(30, 40)))
... # doctest: +ELLIPSIS
[0, ..., 4, 10, ..., 19, 30, ..., 39]

Observera att eftersom alla alternativ är inaktiverade som standard och direktiv endast gäller för det exempel de förekommer i, är aktivering av alternativ (via + i ett direktiv) vanligtvis det enda meningsfulla valet. Alternativflaggor kan emellertid också skickas till funktioner som kör doctests och fastställa olika standardvärden. I sådana fall kan det vara användbart att inaktivera ett alternativ via - i ett direktiv.

Varningar

doctest är seriös när det gäller att kräva exakta matchningar i förväntad utdata. Om inte ens ett enda tecken matchar, misslyckas testet. Detta kommer förmodligen att överraska dig några gånger, eftersom du lär dig exakt vad Python gör och inte garanterar om utdata. Till exempel, när du skriver ut en uppsättning garanterar Python inte att elementen skrivs ut i någon särskild ordning, så ett test som

>>> foo()
{"spam", "eggs"}

är sårbar! En lösning är att göra

>>> foo() == {"spam", "eggs"}
True

istället. Ett annat är att göra

>>> d = sorted(foo())
>>> d
['eggs', 'spam']

Det finns fler, men du förstår säkert.

En annan dålig idé är att skriva ut saker som innehåller en objektadress, t.ex

>>> id(1.0)  # certain to fail some of the time
7948648
>>> class C: pass
>>> C()  # the default repr() for instances embeds an address
<C object at 0x00AC18F0>

Direktivet ELLIPSIS ger en bra metod för det sista exemplet:

>>> C()  # doctest: +ELLIPSIS
<C object at 0x...>

Flyttal är också föremål för små variationer i utdata mellan plattformar, eftersom Python använder plattformens C-bibliotek för vissa beräkningar med flyttal, och C-biblioteken varierar mycket i kvalitet här:

>>> 1000**0.1  # risky
1.9952623149688797
>>> round(1000**0.1, 9) # safer
1.995262315
>>> print(f'{1000**0.1:.4f}') # much safer
1.9953

Tal av formen I/2.**J är säkra på alla plattformar, och jag hittar ofta på doctest-exempel för att producera tal av den formen:

>>> 3./4  # utterly safe
0.75

Enkla bråk är också lättare för människor att förstå, och det ger bättre dokumentation.

Grundläggande API

Funktionerna testmod() och testfile() ger ett enkelt gränssnitt till doctest som bör vara tillräckligt för de flesta grundläggande användningsområden. För en mindre formell introduktion till dessa två funktioner, se avsnitten Enkel användning: Kontrollera exempel i dokumentsträngar och Enkel användning: Kontrollera exempel i en textfil.

doctest.testfile(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, parser=DocTestParser(), encoding=None)

Alla argument utom filnamn är valfria och bör anges i nyckelordsform.

Testa exempel i filen med namnet filnamn. Returnerar (misslyckande_antal, test_antal).

Det valfria argumentet module_relative anger hur filnamnet ska tolkas:

  • Om module_relative är True (standard), anger filename en OS-oberoende modulrelativ sökväg. Som standard är denna sökväg relativ till den anropande modulens katalog, men om argumentet package anges är den relativ till det paketet. För att säkerställa operativsystemsoberoende bör filename använda tecknet / för att separera sökvägssegment och får inte vara en absolut sökväg (dvs. den får inte börja med /).

  • Om module_relative är False, anger filnamn en OS-specifik sökväg. Sökvägen kan vara absolut eller relativ; relativa sökvägar löses med avseende på den aktuella arbetskatalogen.

Det valfria argumentet name anger namnet på testet; som standard, eller om None, används os.path.basename(filnamn).

Valfritt argument package är ett Python-paket eller namnet på ett Python-paket vars katalog ska användas som baskatalog för ett modulrelativt filnamn. Om inget paket anges används den anropande modulens katalog som baskatalog för modulrelativa filnamn. Det är ett fel att ange package om module_relative är False.

Det valfria argumentet globs ger en dict som ska användas som globaler när exempel körs. En ny ytlig kopia av denna dict skapas för doctestet, så att dess exempel börjar med ett rent blad. Som standard, eller om None, används en ny tom dict.

Det valfria argumentet extraglobs ger en dict som sammanfogats till de globaler som används för att exekvera exempel. Detta fungerar som dict.update(): om globs och extraglobs har en gemensam nyckel, visas det associerade värdet i extraglobs i den kombinerade dict. Som standard, eller om None, används inga extra globaler. Detta är en avancerad funktion som gör det möjligt att parametrisera doctests. Till exempel kan ett doctest skrivas för en basklass, med ett generiskt namn för klassen, och sedan återanvändas för att testa valfritt antal underklasser genom att skicka en extraglobs-dict som mappar det generiska namnet till den underklass som ska testas.

Det valfria argumentet verbose skriver ut en massa saker om det är sant, och skriver bara ut fel om det är falskt; som standard, eller om None, är det sant om och endast om '-v' finns i sys.argv.

Det valfria argumentet report skriver ut en sammanfattning i slutet när det är sant, annars skrivs ingenting ut i slutet. I verbose-läge är sammanfattningen detaljerad, annars är sammanfattningen mycket kort (i själva verket tom om alla tester är godkända).

Det valfria argumentet optionflags (standardvärde 0) tar bitwise OR av optionsflaggor. Se avsnitt Flaggor för alternativ.

Det valfria argumentet raise_on_error är som standard false. Om det är sant utlöses ett undantag vid det första felet eller oväntade undantaget i ett exempel. Detta gör att misslyckanden kan felsökas efteråt. Standardbeteendet är att fortsätta köra exempel.

Det valfria argumentet parser anger en DocTestParser (eller underklass) som ska användas för att extrahera tester från filerna. Standardvärdet är en normal parser (dvs. DocTestParser()).

Det valfria argumentet encoding anger en kodning som ska användas för att konvertera filen till unicode.

doctest.testmod(m=None, name=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, exclude_empty=False)

Alla argument är valfria och alla utom m ska anges i nyckelordsform.

Testexempel i dokumentationssträngar i funktioner och klasser som kan nås från modul m (eller modul __main__ om m inte anges eller är None), med början i m.__doc__.

Testa även exempel som kan nås från dict m.__test__, om den finns. m.__test__ mappar namn (strängar) till funktioner, klasser och strängar; funktions- och klassdokstrings söks efter exempel; strängar söks direkt, som om de vore dokstrings.

Endast dokumentsträngar som är kopplade till objekt som tillhör modul m söks.

Return (failure_count, test_count).

Det valfria argumentet name anger namnet på modulen; som standard, eller om None, används m.__name__.

Det valfria argumentet exclude_empty är som standard false. Om det är sant utesluts objekt för vilka inga doctests hittas från att beaktas. Standardvärdet är ett hack för bakåtkompatibilitet, så att kod som fortfarande använder doctest.master.summarize i kombination med testmod() fortsätter att få utdata för objekt utan tester. Argumentet exclude_empty till den nyare DocTestFinder-konstruktorn är som standard true.

De valfria argumenten extraglobs, verbose, report, optionflags, raise_on_error och globs är desamma som för funktionen testfile() ovan, förutom att globs som standard är m.__dict__.

doctest.run_docstring_examples(f, globs, verbose=False, name='NoName', compileflags=None, optionflags=0)

Testexempel som är associerade med objektet f; f kan t.ex. vara en sträng, en modul, en funktion eller ett klassobjekt.

En ytlig kopia av ordboksargumentet globs används för exekveringskontexten.

Det valfria argumentet name används i felmeddelanden och är som standard "NoName".

Om det valfria argumentet verbose är true, genereras utdata även om det inte finns några fel. Som standard genereras utdata endast i händelse av ett exempel på fel.

Det valfria argumentet compileflags anger den uppsättning flaggor som ska användas av Python-kompilatorn när exemplen körs. Som standard, eller om None, härleds flaggor som motsvarar den uppsättning framtida funktioner som finns i globs.

Det valfria argumentet optionflags fungerar som för funktionen testfile() ovan.

Unittest API

När din samling av doctest’ed-moduler växer, kommer du att vilja ha ett sätt att köra alla deras doctests systematiskt. doctest tillhandahåller två funktioner som kan användas för att skapa unittest testsviter från moduler och textfiler som innehåller doctests. För att integrera med unittest testupptäckt, inkludera en load_tests funktion i din testmodul:

import unittest
import doctest
import my_module_with_doctests

def load_tests(loader, tests, ignore):
    tests.addTests(doctest.DocTestSuite(my_module_with_doctests))
    return tests

Det finns två huvudfunktioner för att skapa unittest.TestSuite-instanser från textfiler och moduler med doctests:

doctest.DocFileSuite(*paths, module_relative=True, package=None, setUp=None, tearDown=None, globs=None, optionflags=0, parser=DocTestParser(), encoding=None)

Konvertera doctest-tester från en eller flera textfiler till en unittest.TestSuite.

Den returnerade unittest.TestSuite ska köras av unittest-ramverket och kör de interaktiva exemplen i varje fil. Om ett exempel i någon fil misslyckas, misslyckas det syntetiserade enhetstestet och ett failureException-undantag skapas som visar namnet på filen som innehåller testet och ett (ibland ungefärligt) radnummer. Om alla exempel i en fil hoppas över markeras även det syntetiserade enhetstestet som överhoppat.

Skicka en eller flera sökvägar (som strängar) till textfiler som ska undersökas.

Alternativ kan anges som nyckelordsargument:

Det valfria argumentet module_relative anger hur filnamnen i paths ska tolkas:

  • Om module_relative är True (standard), anger varje filnamn i paths en OS-oberoende modulrelativ sökväg. Som standard är denna sökväg relativ till den anropande modulens katalog, men om argumentet package anges är den relativ till det paketet. För att säkerställa operativsystemsoberoende bör varje filnamn använda tecknet / för att separera sökvägssegment och får inte vara en absolut sökväg (dvs. den får inte börja med /).

  • Om module_relative är False, anger varje filnamn i paths en OS-specifik sökväg. Sökvägen kan vara absolut eller relativ; relativa sökvägar löses med avseende på den aktuella arbetskatalogen.

Det valfria argumentet package är ett Python-paket eller namnet på ett Python-paket vars katalog ska användas som baskatalog för modulrelativa filnamn i paths. Om inget paket anges används den anropande modulens katalog som baskatalog för modulrelativa filnamn. Det är ett fel att ange package om module_relative är False.

Det valfria argumentet setUp anger en konfigurationsfunktion för testsviten. Denna anropas innan testerna i varje fil körs. Funktionen setUp får ett objekt av DocTest. Funktionen setUp kan komma åt testglobalerna som attributet globs för det test som skickas.

Det valfria argumentet tearDown anger en nedmonteringsfunktion för testsviten. Denna anropas efter att testerna i varje fil har körts. Funktionen tearDown kommer att få ett objekt av DocTest. Funktionen tearDown kan komma åt testglobalerna som attributet globs i det test som skickas.

Det valfria argumentet globs är en ordbok som innehåller de första globala variablerna för testerna. En ny kopia av denna ordbok skapas för varje test. Som standard är globs en ny tom ordbok.

Det valfria argumentet optionflags anger standardalternativen för doctest för testerna, som skapas genom att kombinera enskilda alternativflaggor. Se avsnitt Flaggor för alternativ. Se funktionen set_unittest_reportflags() nedan för ett bättre sätt att ställa in rapporteringsalternativ.

Det valfria argumentet parser anger en DocTestParser (eller underklass) som ska användas för att extrahera tester från filerna. Standardvärdet är en normal parser (dvs. DocTestParser()).

Det valfria argumentet encoding anger en kodning som ska användas för att konvertera filen till unicode.

Den globala __file__ läggs till i de globaler som tillhandahålls för doctests som laddas från en textfil med DocFileSuite().

doctest.DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, setUp=None, tearDown=None, optionflags=0, checker=None)

Konvertera doctest-tester för en modul till en unittest.TestSuite.

Den returnerade unittest.TestSuite ska köras av unittest-ramverket och kör varje doctest i modulen. Varje dokumentsträng körs som ett separat enhetstest. Om något av doctesterna misslyckas, misslyckas det syntetiserade enhetstestet och ett unittest.TestCase.failureException-undantag skapas som visar namnet på filen som innehåller testet och ett (ibland ungefärligt) radnummer. Om alla exempel i en dokumentsträng hoppas över, kommer

Det valfria argumentet module anger vilken modul som ska testas. Det kan vara ett modulobjekt eller ett (eventuellt prickat) modulnamn. Om det inte anges används den modul som anropar denna funktion.

Det valfria argumentet globs är en ordbok som innehåller de första globala variablerna för testerna. En ny kopia av denna dictionary skapas för varje test. Som standard är globs modulens __dict__.

Det valfria argumentet extraglobs anger en extra uppsättning globala variabler som slås samman med globs. Som standard används inga extra globala variabler.

Valfritt argument test_finder är DocTestFinder-objektet (eller en direkt ersättare) som används för att extrahera doctests från modulen.

De valfria argumenten setUp, tearDown och optionflags är desamma som för funktionen DocFileSuite() ovan, men de anropas för varje dokumentsträng.

Denna funktion använder samma sökteknik som testmod().

Ändrad i version 3.5: DocTestSuite() returnerar en tom unittest.TestSuite om modul inte innehåller några docstrings istället för att ge ValueError.

Under täckmanteln skapar DocTestSuite() en unittest.TestSuite av doctest.DocTestCase-instanser, och DocTestCase är en underklass till unittest.TestCase. DocTestCase dokumenteras inte här (det är en intern detalj), men att studera dess kod kan svara på frågor om de exakta detaljerna i unittest-integrationen.

På samma sätt skapar DocFileSuite() en unittest.TestSuite av doctest.DocFileCase-instanser, och DocFileCase är en subklass av DocTestCase.

Så båda sätten att skapa en unittest.TestSuite kör instanser av DocTestCase. Detta är viktigt av en subtil anledning: när du kör doctest-funktioner själv, kan du styra doctest-alternativen som används direkt, genom att skicka alternativflaggor till doctest-funktioner. Men om du skriver ett unittest-ramverk, kontrollerar unittest i slutändan när och hur tester körs. Ramverkets författare vill vanligtvis kontrollera doctest rapporteringsalternativ (kanske, t.ex., specificerade av kommandoradsalternativ), men det finns inget sätt att skicka alternativ genom unittest till doctest testlöpare.

Av denna anledning stödjer doctest också ett begrepp som doctest som rapporterar flaggor som är specifika för unittest-stöd, via denna funktion:

doctest.set_unittest_reportflags(flags)

Ange vilka doctest-rapporteringsflaggor som ska användas.

Argument flags tar bitvis ELLER av alternativflaggor. Se avsnitt Flaggor för alternativ. Endast ”rapporteringsflaggor” kan användas.

Detta är en modul-global inställning, och påverkar alla framtida doctest som körs av modulen unittest: runTest()-metoden i DocTestCase tittar på de alternativflaggor som specificerades för testfallet när DocTestCase-instansen konstruerades. Om inga rapporteringsflaggor specificerades (vilket är det typiska och förväntade fallet), doctest unittest rapporteringsflaggor är bitwise ORed i alternativflaggorna, och alternativflaggorna så förstärkta skickas till DocTestRunner instansen skapad för att köra doctestet. Om några rapporteringsflaggor specificerades när DocTestCase-instansen konstruerades, ignoreras doctest:s unittest rapporteringsflaggor.

Funktionen returnerar värdet på unittest-rapporteringsflaggorna som gällde innan funktionen anropades.

Avancerat API

Det grundläggande API:et är en enkel wrapper som är avsedd att göra doctest lätt att använda. Det är ganska flexibelt och bör uppfylla de flesta användares behov; men om du behöver mer finkornig kontroll över testningen eller vill utöka doctests funktioner bör du använda det avancerade API:et.

Det avancerade API:et kretsar kring två containerklasser som används för att lagra de interaktiva exempel som hämtas från doctest-fall:

  • Exempel: En enda Python statement, parat med dess förväntade resultat.

  • DocTest: En samling av Example, vanligtvis extraherade från en enda dokumentsträng eller textfil.

Ytterligare bearbetningsklasser definieras för att hitta, analysera och köra samt kontrollera doctest-exempel:

  • DocTestFinder: Hittar alla dokumentsträngar i en given modul och använder en DocTestParser för att skapa en DocTest från varje dokumentsträng som innehåller interaktiva exempel.

  • DocTestParser: Skapar ett DocTest-objekt från en sträng (t.ex. ett objekts docstring).

  • DocTestRunner: Exekverar exemplen i en DocTest och använder en OutputChecker för att verifiera utdata.

  • OutputChecker: Jämför den faktiska utdata från ett doctest-exempel med den förväntade utdata och avgör om de stämmer överens.

Relationerna mellan dessa bearbetningsklasser sammanfattas i följande diagram:

                            list of:
+------+                   +---------+
|module| --DocTestFinder-> | DocTest | --DocTestRunner-> results
+------+    |        ^     +---------+     |       ^    (printed)
            |        |     | Example |     |       |
            v        |     |   ...   |     v       |
           DocTestParser   | Example |   OutputChecker
                           +---------+

DocTest-objekt

class doctest.DocTest(examples, globs, name, filename, lineno, docstring)

En samling doctest-exempel som bör köras i ett enda namnrymd. Argumenten i konstruktorn används för att initiera attributen med samma namn.

DocTest definierar följande attribut. De initialiseras av konstruktören och bör inte modifieras direkt.

examples

En lista med Example-objekt som kodar för de enskilda interaktiva Python-exempel som ska köras av detta test.

globs

Namnrymden (även kallad globals) som exemplen ska köras i. Detta är en ordbok som mappar namn till värden. Alla ändringar i namnrymden som görs av exemplen (t.ex. bindning av nya variabler) kommer att återspeglas i globs efter att testet har körts.

name

Ett strängnamn som identifierar DocTest. Vanligtvis är detta namnet på det objekt eller den fil som testet extraherades från.

filename

Namnet på filen som detta DocTest extraherades från; eller None om filnamnet är okänt, eller om DocTest inte extraherades från en fil.

lineno

Radnumret i filename där denna DocTest börjar, eller None om radnumret inte är tillgängligt. Radnumret är nollbaserat i förhållande till början av filen.

docstring

Den sträng som testet extraherades från, eller None om strängen inte är tillgänglig, eller om testet inte extraherades från en sträng.

Exempel på objekt

class doctest.Example(source, want, exc_msg=None, lineno=0, indent=0, options=None)

Ett enda interaktivt exempel som består av en Python-sats och dess förväntade utdata. Argumenten i konstruktorn används för att initiera attributen med samma namn.

Example definierar följande attribut. De initialiseras av konstruktören och bör inte modifieras direkt.

source

En sträng som innehåller exemplets källkod. Källkoden består av en enda Python-sats och avslutas alltid med en ny rad; konstruktören lägger till en ny rad när det behövs.

want

Den förväntade utdata från körning av exemplets källkod (antingen från stdout eller en spårning vid undantag). want slutar med en ny rad om ingen utdata förväntas, i vilket fall det är en tom sträng. Konstruktören lägger till en ny rad när det behövs.

exc_msg

Det undantagsmeddelande som genereras av exemplet, om exemplet förväntas generera ett undantag; eller None om det inte förväntas generera ett undantag. Detta undantagsmeddelande jämförs med returvärdet för traceback.format_exception_only(). exc_msg slutar med en ny rad om det inte är None. Konstruktören lägger till en ny rad om det behövs.

lineno

Radnumret i den sträng som innehåller detta exempel där exemplet börjar. Radnumret är nollbaserat i förhållande till början av den sträng som innehåller exemplet.

indent

Exemplets indrag i den innehållande strängen, dvs. antalet mellanslagstecken som föregår exemplets första prompt.

options

En ordbok som mappar från alternativflaggor till True eller False, som används för att åsidosätta standardalternativ för detta exempel. Alla alternativflaggor som inte finns i denna ordbok lämnas med sitt standardvärde (som anges av DocTestRunner optionflags). Som standard är inga alternativ inställda.

DocTestFinder-objekt

class doctest.DocTestFinder(verbose=False, parser=DocTestParser(), recurse=True, exclude_empty=True)

En bearbetningsklass som används för att extrahera de DocTest s som är relevanta för ett visst objekt, från dess docstring och docstrings för de objekt som ingår. DocTest s kan extraheras från moduler, klasser, funktioner, metoder, staticmethods, classmethods och properties.

Det valfria argumentet verbose kan användas för att visa de objekt som sökts av sökaren. Standardvärdet är False (ingen utdata).

Det valfria argumentet parser anger objektet DocTestParser (eller en direkt ersättare) som används för att extrahera doctests från docstrings.

Om det valfria argumentet recurse är false, kommer DocTestFinder.find() endast att undersöka det givna objektet, och inte några ingående objekt.

Om det valfria argumentet exclude_empty är false, kommer DocTestFinder.find() att inkludera tester för objekt med tomma dokumentsträngar.

DocTestFinder definierar följande metod:

find(obj[, name][, module][, globs][, extraglobs])

Returnerar en lista över DocTest som definieras av objs docstring, eller av någon av dess ingående objekts docstrings.

Det valfria argumentet name anger objektets namn; detta namn kommer att användas för att konstruera namn för de returnerade DocTest s. Om name inte anges används obj.__name__.

Den valfria parametern module är den modul som innehåller det angivna objektet. Om modulen inte anges eller är None, kommer testfinder att försöka att automatiskt bestämma rätt modul. Objektets modul används:

  • Som standardnamnrymd om globs inte anges.

  • För att förhindra DocTestFinder från att extrahera DocTests från objekt som importeras från andra moduler. (Inneslutna objekt med andra moduler än modul ignoreras)

  • För att hitta namnet på den fil som innehåller objektet.

  • För att hjälpa till att hitta radnumret för objektet i dess fil.

Om module är False kommer inget försök att hitta modulen att göras. Detta är oklart och används mest för att testa själva doctest: om module är False, eller är None men inte kan hittas automatiskt, anses alla objekt tillhöra den (icke-existerande) modulen, så alla objekt som ingår kommer (rekursivt) att sökas efter doctests.

Globalerna för varje DocTest bildas genom att kombinera globs och extraglobs (bindningar i extraglobs åsidosätter bindningar i globs). En ny ytlig kopia av globals-ordlistan skapas för varje DocTest. Om globs inte anges är standardvärdet modulens __dict__, om den anges, eller {} annars. Om extraglobs inte anges är standardvärdet {}.

DocTestParser-objekt

class doctest.DocTestParser

En bearbetningsklass som används för att extrahera interaktiva exempel från en sträng och använda dem för att skapa ett DocTest-objekt.

DocTestParser definierar följande metoder:

get_doctest(string, globs, name, filename, lineno)

Extrahera alla doctest-exempel från den angivna strängen och samla dem i ett DocTest-objekt.

globs, name, filename och lineno är attribut för det nya DocTest-objektet. Se dokumentationen för DocTest för mer information.

get_examples(string, name='<string>')

Extraherar alla doctest-exempel från den angivna strängen och returnerar dem som en lista med Example-objekt. Radnummer är 0-baserade. Det valfria argumentet name är ett namn som identifierar den här strängen och används endast för felmeddelanden.

parse(string, name='<string>')

Dela upp den angivna strängen i exempel och mellanliggande text, och returnera dem som en lista med omväxlande Examples och strängar. Radnumren för Example s är 0-baserade. Det valfria argumentet name är ett namn som identifierar den här strängen och används endast för felmeddelanden.

TestResults-objekt

class doctest.TestResults(failed, attempted)
failed

Antal misslyckade tester.

attempted

Antal testförsök.

skipped

Antal överhoppade tester.

Tillagd i version 3.13.

DocTestRunner-objekt

class doctest.DocTestRunner(checker=None, verbose=None, optionflags=0)

En bearbetningsklass som används för att exekvera och verifiera de interaktiva exemplen i en DocTest.

Jämförelsen mellan förväntade utdata och faktiska utdata görs av en OutputChecker. Denna jämförelse kan anpassas med ett antal alternativflaggor; se avsnitt Flaggor för alternativ för mer information. Om optionsflaggorna är otillräckliga kan jämförelsen också anpassas genom att skicka en underklass av OutputChecker till konstruktören.

Testlöparens displayutmatning kan styras på två sätt. För det första kan en utdatafunktion skickas till run(); denna funktion kommer att anropas med strängar som ska visas. Standardvärdet är sys.stdout.write. Om det inte är tillräckligt att fånga utdata kan visningsutdata också anpassas genom att subklassa DocTestRunner och åsidosätta metoderna report_start(), report_success(), report_unexpected_exception() och report_failure().

Det valfria nyckelordsargumentet checker anger objektet OutputChecker (eller en ersättare) som ska användas för att jämföra förväntade utdata med faktiska utdata för doctest-exempel.

Det valfria nyckelordsargumentet verbose styr DocTestRunner s ordrikedom. Om verbose är True, skrivs information ut om varje exempel, allteftersom det körs. Om verbose är False skrivs endast misslyckanden ut. Om verbose är ospecificerat, eller None, så används verbose-utmatning om kommandoradsväxeln -v används.

Det valfria nyckelordsargumentet optionflags kan användas för att styra hur testlöparen jämför förväntade resultat med faktiska resultat och hur den visar misslyckanden. För mer information, se avsnitt Flaggor för alternativ.

Testlöparen samlar in statistik. Det sammanlagda antalet försök, misslyckade och överhoppade exempel är också tillgängligt via attributen tries, failures och skips. Metoderna run() och summarize() returnerar en instans av TestResults.

DocTestRunner definierar följande metoder:

report_start(out, test, example)

Rapporterar att testlöparen håller på att bearbeta det givna exemplet. Denna metod tillhandahålls för att underklasser till DocTestRunner ska kunna anpassa sin utdata; den ska inte anropas direkt.

exempel är det exempel som ska bearbetas. test är testet som innehåller example. out är den utdatafunktion som skickades till DocTestRunner.run().

report_success(out, test, example, got)

Rapportera att det givna exemplet kördes framgångsrikt. Denna metod tillhandahålls för att underklasser till DocTestRunner ska kunna anpassa sin utdata; den ska inte anropas direkt.

example är exemplet som ska bearbetas. got är den faktiska utmatningen från exemplet. test är testet som innehåller example. out är den utdatafunktion som skickades till DocTestRunner.run().

report_failure(out, test, example, got)

Rapportera att det givna exemplet misslyckades. Den här metoden tillhandahålls för att underklasser till DocTestRunner ska kunna anpassa sin utdata; den ska inte anropas direkt.

example är exemplet som ska bearbetas. got är den faktiska utmatningen från exemplet. test är testet som innehåller example. out är den utdatafunktion som skickades till DocTestRunner.run().

report_unexpected_exception(out, test, example, exc_info)

Rapportera att det givna exemplet gav upphov till ett oväntat undantag. Denna metod tillhandahålls för att underklasser till DocTestRunner ska kunna anpassa sina utdata; den ska inte anropas direkt.

example är det exempel som ska bearbetas. exc_info är en tupel som innehåller information om det oväntade undantaget (som returneras av sys.exc_info()). test är testet som innehåller exempel. out är den utdatafunktion som skickades till DocTestRunner.run().

run(test, compileflags=None, out=None, clear_globs=True)

Kör exemplen i test (ett DocTest-objekt) och visa resultaten med hjälp av skrivarfunktionen out. Returnerar en instans av TestResults.

Exemplen körs i namnrymden test.globs. Om clear_globs är true (standard) kommer detta namnrymd att rensas efter att testet har körts, för att hjälpa till med skräpsamlingen. Om du vill undersöka namnrymden efter att testet har slutförts använder du clear_globs=False.

compileflags anger den uppsättning flaggor som ska användas av Python-kompilatorn när exemplen körs. Om den inte anges kommer den som standard att använda den uppsättning flaggor för framtida import som gäller för globs.

Utdata för varje exempel kontrolleras med hjälp av DocTestRunner:s utdatakontroll och resultaten formateras med DocTestRunner.report_*()-metoderna.

summarize(verbose=None)

Skriv ut en sammanfattning av alla testfall som har körts av denna DocTestRunner, och returnera en TestResults-instans.

Det valfria argumentet verbose styr hur detaljerad sammanfattningen är. Om ordrikhet inte anges används DocTestRunner:s ordrikhet.

DocTestParser har följande attribut:

tries

Antal försök till exempel.

failures

Antal misslyckade exempel.

skips

Antal överhoppade exempel.

Tillagd i version 3.13.

OutputChecker-objekt

class doctest.OutputChecker

En klass som används för att kontrollera om den faktiska utmatningen från ett doctest-exempel matchar den förväntade utmatningen. OutputChecker definierar två metoder: check_output(), som jämför ett givet par utmatningar och returnerar True om de matchar; och output_difference(), som returnerar en sträng som beskriver skillnaderna mellan två utmatningar.

OutputChecker definierar följande metoder:

check_output(want, got, optionflags)

Returnerar True om den faktiska utdata från ett exempel (got) matchar den förväntade utdata (want). Dessa strängar anses alltid matcha om de är identiska; men beroende på vilka alternativflaggor testköraren använder är flera icke-exakta matchningstyper också möjliga. Se avsnitt Flaggor för alternativ för mer information om alternativflaggor.

output_difference(example, got, optionflags)

Returnerar en sträng som beskriver skillnaderna mellan det förväntade utfallet för ett visst exempel (example) och det faktiska utfallet (got). optionflags är den uppsättning optionsflaggor som används för att jämföra want och got.

Felsökning

Doctest tillhandahåller flera mekanismer för felsökning av doctest-exempel:

  • Flera funktioner konverterar doctests till körbara Python-program, som kan köras under Pythons debugger, pdb.

  • Klassen DebugRunner är en underklass till DocTestRunner som skapar ett undantag för det första misslyckade exemplet och innehåller information om det exemplet. Denna information kan användas för att utföra felsökning av exemplet efteråt.

  • De unittest-fall som genereras av DocTestSuite() stöder debug()-metoden som definieras av unittest.TestCase.

  • Du kan lägga till ett anrop till pdb.set_trace() i ett doctest-exempel, och du kommer att hamna i Pythons debugger när den raden körs. Sedan kan du inspektera aktuella värden för variabler och så vidare. Anta till exempel att a.py innehåller just den här modulen docstring:

    """
    >>> def f(x):
    ...     g(x*2)
    >>> def g(x):
    ...     print(x+3)
    ...     import pdb; pdb.set_trace()
    >>> f(3)
    9
    """
    

    Då kan en interaktiv Python-session se ut så här:

    >>> import a, doctest
    >>> doctest.testmod(a)
    --Return--
    > <doctest a[1]>(3)g()->None
    -> import pdb; pdb.set_trace()
    (Pdb) list
      1     def g(x):
      2         print(x+3)
      3  ->     import pdb; pdb.set_trace()
    [EOF]
    (Pdb) p x
    6
    (Pdb) step
    --Return--
    > <doctest a[0]>(2)f()->None
    -> g(x*2)
    (Pdb) list
      1     def f(x):
      2  ->     g(x*2)
    [EOF]
    (Pdb) p x
    3
    (Pdb) step
    --Return--
    > <doctest a[2]>(1)?()->None
    -> f(3)
    (Pdb) cont
    (0, 3)
    >>>
    

Funktioner som konverterar doctests till Python-kod och eventuellt kör den syntetiserade koden under felsökaren:

doctest.script_from_examples(s)

Konvertera text med exempel till ett skript.

Argument s är en sträng som innehåller doctest-exempel. Strängen konverteras till ett Python-skript, där doctest-exemplen i s konverteras till vanlig kod och allt annat konverteras till Python-kommentarer. Det genererade skriptet returneras som en sträng. Till exempel

import doctest
print(doctest.script_from_examples(r"""
    Set x and y to 1 and 2.
    >>> x, y = 1, 2

    Print their sum:
    >>> print(x+y)
    3
"""))

visar:

# Ställ in x och y till 1 och 2.
x, y = 1, 2
#
# Skriv ut deras summa:
print(x+y)
# Förväntat:
## 3

Denna funktion används internt av andra funktioner (se nedan), men kan också vara användbar när du vill omvandla en interaktiv Python-session till ett Python-skript.

doctest.testsource(module, name)

Konvertera doctestet för ett objekt till ett skript.

Argument module är ett modulobjekt, eller ett punktat namn på en modul, som innehåller det objekt vars doctests är av intresse. Argument name är namnet (inom modulen) på objektet med de doctests som är av intresse. Resultatet är en sträng som innehåller objektets dokumentsträng konverterad till ett Python-skript, enligt beskrivningen för script_from_examples() ovan. Om till exempel modulen a.py innehåller en toppnivåfunktion f(), så är

import a, doctest
print(doctest.testsource(a, "a.f"))

skriver ut en skriptversion av funktionen f()’s docstring, med doctests konverterade till kod och resten placerade i kommentarer.

doctest.debug(module, name, pm=False)

Felsök doctesterna för ett objekt.

Argumenten module och name är desamma som för funktionen testsource() ovan. Det syntetiserade Python-skriptet för det namngivna objektets docstring skrivs till en temporär fil, och sedan körs filen under kontroll av Python-debuggern, pdb.

En ytlig kopia av module.__dict__ används för både lokal och global exekveringskontext.

Det valfria argumentet pm styr om felsökning efter avslutad körning ska användas. Om pm har ett sant värde körs skriptfilen direkt och felsökaren blir inblandad endast om skriptet avslutas genom att ett ohanterat undantag uppstår. Om så är fallet aktiveras post-mortem-felsökning via pdb.post_mortem(), som skickar spårningsobjektet från det ohanterade undantaget. Om pm inte anges, eller är false, körs skriptet under debuggern från början, genom att skicka ett lämpligt exec()-anrop till pdb.run().

doctest.debug_src(src, pm=False, globs=None)

Felsök doctesterna i en sträng.

Detta är som funktionen debug() ovan, förutom att en sträng som innehåller doctest-exempel anges direkt via argumentet src.

Det valfria argumentet pm har samma betydelse som i funktionen debug() ovan.

Det valfria argumentet globs anger en ordbok som ska användas som både lokalt och globalt exekveringskontext. Om det inte anges, eller None, används en tom ordbok. Om det anges används en ytlig kopia av ordlistan.

Klassen DebugRunner, och de speciella undantag som den kan ge upphov till, är av störst intresse för utvecklare av testramverk och kommer endast att beskrivas översiktligt här. Se källkoden, och särskilt DebugRunner s docstring (som är ett doctest!) för mer information:

class doctest.DebugRunner(checker=None, verbose=None, optionflags=0)

En underklass till DocTestRunner som ger upphov till ett undantag så snart ett fel uppstår. Om ett oväntat undantag inträffar, skapas ett UnexpectedException-undantag som innehåller testet, exemplet och det ursprungliga undantaget. Om utdata inte stämmer överens skapas ett DocTestFailure-undantag som innehåller testet, exemplet och den faktiska utdatan.

För information om konstruktörens parametrar och metoder, se dokumentationen för DocTestRunner i avsnitt Avancerat API.

Det finns två undantag som kan uppstå i DebugRunner-instanser:

exception doctest.DocTestFailure(test, example, got)

Ett undantag som tas upp av DocTestRunner för att signalera att ett doctest-exempels faktiska resultat inte stämde överens med det förväntade resultatet. Argumenten i konstruktorn används för att initiera attributen med samma namn.

DocTestFailure definierar följande attribut:

DocTestFailure.test

Objektet DocTest som kördes när exemplet misslyckades.

DocTestFailure.example

Den Example som misslyckades.

DocTestFailure.got

Exemplets faktiska utdata.

exception doctest.UnexpectedException(test, example, exc_info)

Ett undantag som skapas av DocTestRunner för att signalera att ett doctest-exempel skapade ett oväntat undantag. Argumenten i konstruktorn används för att initiera attributen med samma namn.

UnexpectedException definierar följande attribut:

UnexpectedException.test

Objektet DocTest som kördes när exemplet misslyckades.

UnexpectedException.example

Den Example som misslyckades.

UnexpectedException.exc_info

En tupel som innehåller information om det oväntade undantaget, som returneras av sys.exc_info().

Soapbox

Som nämndes i inledningen har doctest vuxit till att ha tre primära användningsområden:

  1. Kontroll av exempel i docstrings.

  2. Regressionstestning.

  3. Exekverbar dokumentation / litterat test.

Dessa användningsområden har olika krav, och det är viktigt att skilja dem åt. Framför allt blir dokumentationen dålig om man fyller den med obskyra testfall.

När du skriver en docstring ska du välja docstring-exempel med omsorg. Det här är en konst som måste läras - det kanske inte är naturligt i början. Exemplen bör tillföra dokumentationen ett verkligt värde. Ett bra exempel kan ofta vara värt många ord. Om du gör det med omsorg kommer exemplen att vara ovärderliga för dina användare och betala tillbaka den tid det tar att samla in dem många gånger om när åren går och saker och ting förändras. Jag är fortfarande förvånad över hur ofta ett av mina doctest-exempel slutar fungera efter en ”harmlös” förändring.

Doctest är också ett utmärkt verktyg för regressionstestning, särskilt om man inte snålar med den förklarande texten. Genom att varva prosa och exempel blir det mycket lättare att hålla reda på vad som faktiskt testas och varför. När ett test misslyckas kan bra prosa göra det mycket lättare att räkna ut vad problemet är och hur det ska åtgärdas. Det är sant att man kan skriva omfattande kommentarer i kodbaserade tester, men det är få programmerare som gör det. Många har upptäckt att man får mycket tydligare tester om man istället använder sig av doctest-metoder. Kanske beror det helt enkelt på att doctest gör det lite enklare att skriva prosa än att skriva kod, medan det är lite svårare att skriva kommentarer i kod. Jag tror att det går djupare än så: den naturliga inställningen när man skriver ett doctest-baserat test är att man vill förklara de små detaljerna i sin programvara och illustrera dem med exempel. Detta leder i sin tur naturligt till testfiler som börjar med de enklaste funktionerna och logiskt går vidare till komplikationer och kantfall. Resultatet blir en sammanhängande berättelse i stället för en samling isolerade funktioner som testar isolerade bitar av funktionalitet till synes slumpmässigt. Det är en annan attityd som ger andra resultat och suddar ut skillnaden mellan att testa och att förklara.

Regressionstester bör helst begränsas till särskilda objekt eller filer. Det finns flera alternativ för att organisera tester:

  • Skriv textfiler som innehåller testfall som interaktiva exempel och testa filerna med testfile() eller DocFileSuite(). Detta rekommenderas, men är lättast att göra för nya projekt som redan från början är utformade för att använda doctest.

  • Definiera funktioner med namnet _regrtest_topic som består av enskilda dokumentsträngar som innehåller testfall för de namngivna ämnena. Dessa funktioner kan inkluderas i samma fil som modulen, eller separeras till en separat testfil.

  • Definiera en __test__-ordbok som mappar från regressionstestämnen till dokumentsträngar som innehåller testfall.

När du har placerat dina tester i en modul kan modulen själv vara testköraren. När ett test misslyckas kan du ordna så att din testkörare bara kör om det misslyckade testet medan du felsöker problemet. Här är ett minimalt exempel på en sådan testlöpare:

if __name__ == '__main__':
    import doctest
    flags = doctest.REPORT_NDIFF|doctest.FAIL_FAST
    if len(sys.argv) > 1:
        name = sys.argv[1]
        if name in globals():
            obj = globals()[name]
        else:
            obj = __test__[name]
        doctest.run_docstring_examples(obj, globals(), name=name,
                                       optionflags=flags)
    else:
        fail, total = doctest.testmod(optionflags=flags)
        print(f"{fail} failures out of {total} tests")

Fotnoter