Leren Programmeren in Python: Checklists
Welke checklists aan bod komen:
- De plaats in een programma waar je merkt dat het faalt,
is vaak niet de plaats waar een defect zit.
- Als er een Python foutmelding is verschenen,
raadpleeg dan de
checklist voor veelvoorkomende Python foutmeldingen.
- Als het programma niet goed werkt,
maar er geen Python foutmelding wordt gegeven,
lees dan eerst het programma na aan de hand van de
checklist hieronder
en controleer het op defecten.
- Lees de specificatie en het ontwerp na.
Misschien heb je iets over het hoofd gezien.
- Ga na of het falen reproduceerbaar is.
- Voer ook andere testgevallen uit.
- Bedenk eventueel nieuwe testgevallen.
Voeg ze toe aan het testplan als ze bijgedragen hebben tot het vinden van een defect.
- Inspecteer na eindiging van het programma interactief de relevante variabelen
(als de IDE dat toelaat).
Voeg eventueel tijdelijk een print-opdracht toe om de waarden van variabelen te tonen.
Beëindig eventueel tijdelijk het programma voortijdig
door de opdracht assert False
tussen te voegen,
of assert conditie
om alleen te stoppen als conditie NIET geldt.
Als de tussengevoegde opdrachten niet meer nodig zijn,
dan kun je ze "uitschakelen" door er een # voor te zetten.
Bij nalezen van code kun je defecten ontdekken die bij testen
onopgemerkt blijven of moeilijk te localiseren zijn.
Een falende test wijst op een defect,
maar een programma dat zelfs bij herhaald gebruik niet faalt kan toch defecten bevatten.
Zelfs als een programma faalt,
is vaak niet duidelijk waar de defecten zitten.
Hier is een eenvoudige checklist om je te leiden bij het nalezen.
- Is de opmaak systematisch?
Spatiëring, lege regels, inspringen, regellengte, geen TAB.
- Is het commentaar in orde?
Aanhef van programma ("""...""", __author__ = "...") en
ontwerpverwijzingen (##).
Waar nodig interpretaties (#) en asserties (#@).
Geen overbodig commentaar.
Specificatie bij definitie van routine ("""...""").
- Zijn alle namen zinvol en zijn ze correct gespeld?
In Python zijn hoofdletters en kleine letters verschillend.
- Zijn de relevante variabelen goed geïnitialiseerd?
Beginwaarde toekennen, m.n. vóór herhalingen (for en while).
- Kloppen de condities in selecties (if) en herhalingen (while)?
Is het duidelijk waarom een while-herhaling zal eindigen?
Introduceer hulpvariabelen om ingewikkelde condities te vereenvoudigen.
- Kloppen de uitdrukkingen in toekenningen en routine-aanroepen?
Staan er ook haakjes bij een routine-aanroep zonder argumenten,
zoals rij.sort()?
Klopt de volgorde van parameters in routine-aanroepen?
Introduceer eventueel hulpvariabelen om ingewikkelde uitdrukkingen te vereenvoudigen.
- Zijn karakterrijen precies volgens specificatie geschreven?
M.n. in uitvoer met print en bij
formaataanpassing met %.
- Zijn bestanden goed geopend met
file(name, mode)?
Juiste name;
juiste mode: lezen ('r'), schrijven ('w'), uitbreiden ('a').
- Zijn de globale variabelen, die een routine moet kunnen wijzigen,
erin aangekondigd met global?
- Zijn slechte stijlfiguren vermeden?
Zie hieronder.
- Voor geavanceerdere controle:
- Worden relevante excepties met try-opdrachten afgevangen?
- Worden kritische voorwaarden met assert-opdrachten gecontroleerd?
De volgende tabel bevat voorbeelden van slechte stijl en hoe
het beter kan.
Slechte stijl | Beter | Opmerkingen |
if conditie :
blok1
if not conditie :
blok2 |
if conditie :
blok1
else :
blok2 |
De "verbetering" is niet van toepassing indien
uitvoering van blok1 de waarde van conditie wijzigt.
Maar dan moet er wel commentaar bij om hier op te wijzen.
|
if conditie1 :
blok1
else :
if conditie2 :
blok2
else :
blok3 |
if conditie1 :
blok1
elif conditie2 :
blok2
else :
blok3 |
De "verbetering" is niet van toepassing indien
het onderscheid o.g.v. conditie2 heel anders van aard is
dan bij conditie1.
Extra commentaar is dan gewenst.
|
|
|
De toevoeging == True is overbodig.
Je schrijf toch ook niet (conditie == True) == True?
|
|
|
|
Testen is het doelgericht zoeken naar defecten in een programma
door het programma systematisch te gebruiken en het gedrag ervan te controleren
tegen de specificatie.
Hoe je van plan bent een programma te testen staat in het
testplan (voorbeeld).
Let bij het opstellen van een testplan op de volgende zaken.
- Is het testplan vooraf helemaal "op schrift" gezet?
- Is elk testgeval voorzien van een identificatie,
zoals een volgnummer?
- Is concrete invoer vermeld?
Kun je die letterlijk overnemen (kopiëren/plakken)?
- Is de bijbehorende verwachte uitvoer vermeld?
Is duidelijk waarom die goed is?
Is duidelijk hoe je de werkelijke uitvoer hiertegen controleert?
Hoe zit het met verwachte nauwkeurigheid en snelheid?
- Is bij elk testgeval een motivatie vermeld?
- Is het duidelijk in welke volgorde in- en uitvoer elkaar dienen af te wisselen?
- Is er voldoende variatie in de testgevallen?
Wordt elke opdracht van het programma in ten minste één testgeval uitgevoerd?
Wordt elke "tak" van een selectie in ten minste één testgeval doorlopen?
Zijn minimale en maximale waarden net binnen de grenzen geprobeerd?
- Is het testplan bijgesteld na het maken van aanpassingen aan de code?
M.n. vanwege defecten die ontdekt zijn buiten het testplan om.
- Voor geavanceerder testen:
- Hoe zit het met geheugengebruik?
- Zijn assert-opdrachten in de code opgenomen
om belangrijke condities te controleren?
- Is ook onverwachte invoer opgenomen?
Reageert het programma hier "redelijk" op?
- Is PyUnit gebruikt?
Module unittest: Python unit testing framework
Let bij het uitvoeren van een testplan op de volgende zaken.
- Doorloop de testgevallen precies volgens het testplan:
- Houd dezelfde volgorde aan.
- Gebruik exact de aangegeven invoer.
- Controleer de geproduceerde uitvoer tegen de verwachte uitvoer.
- Zijn alle testgevallen van het testplan uitgevoerd?
N.B. Localiseren en verwijderen van defecten is geen onderdeel van het testen zelf,
maar een aparte activiteit.
Na het verwijderen van defecten is het zaak opnieuw alle testgevallen uit te voeren.
- Is bij elk testgeval de uitvoer gecontroleerd volgens het testplan?
- Zijn er bijzonderheden opgevallen buiten het testplan om?
- Heb je de testuitslag en geproduceerde uitvoer bewaard
in een testrapport?
Vermeld ook de identificatie (volgnummer) van het falende testgeval.
- Als een testgeval faalt, is dat dan reproduceerbaar?
- Zijn er redenen om het testplan aan te passen?
Foutendiagnose is het localiseren van defecten bij een falende test.
Controleer eerst of de code in orde is
volgens bovenstaande checklist.
- AttributeError
- Bij gebruik van een object werd een onbekend attribuut aangesproken.
- Het object ondersteunt de betreffende bewerking niet.
Bijv. regel = 'keyboard'.readline() geeft
AttributeError: 'str' object has no attribute 'readline'
- EOFError
- Het lezen van invoer met input() of raw_input()
stuitte voortijdig op het einde van het bestand (End-Of-File).
- De invoer zelf klopte niet.
- Het programma detecteerde het einde van de invoer niet goed.
- IndexError
- Bij het indexeren van een rij viel de index buiten de grenzen.
- Bij de uitdrukking rij [ index ]
gold niet -len(rij) <= index < len(rij).
N.B. Een negatieve index telt vanaf het einde!
- IOError
- Probleem m.b.t. in- of uitvoer.
- Bestand geopend met file(name,'r') niet gevonden.
Controleer name (mogelijk bestaat een map op het zoekpad niet).
- NameError
- Er werd een naam gebruikt die niet gedefinieerd is.
De naam kan ook in de invoer gestaan hebben.
- De naam is verkeerd gespeld.
- Initialisatie (naam = beginwaarde) of
definitie (def naam ...) is vergeten.
- Aanhalingstekens zijn vergeten bij invoer van karakterrij voor input().
- Functie input() is gebruikt i.p.v. raw_input().
- SyntaxError
- Het programma klopt niet qua syntax (vorm).
- Dubbele punt is vergeten bij if, elif, else, for, while,
def
- De gelijkheidstest is geschreven als = i.p.v. ==.
- De opdrachten in een blok zijn niet allemaal precies even ver ingesprongen.
- Komma's zijn vergeten tussen de uitdrukkingen bij for of print.
- TypeError
- Bij het evalueren van een uitdrukking klopte het type van een object niet bij de toegepaste bewerking of routine.
- Haakjes zijn vergeten bij formaataanpassing
waarbij meer dan één waarde wordt ingevuld, bijv.
print "%d, %d" % 1, 2 i.p.v.
print "%d, %d" % (1, 2).
- ZeroDivisionError
- Bij de bewerking /, // of % op getallen is het tweede argument nul.
Zie ook de checklist voor het nalezen van code.
- Niet-eindigende executie, zonder uitvoer
- De executie van het programma eindigt niet, of lijkt niet te eindigen,
en er wordt geen uitvoer geproduceerd.
- In een IDE kan de executie i.h.a. worden afgebroken
(in IDLE met Ctrl-C).
- Een berekening is erg inefficiënt en kost veel meer tijd dan verwacht.
- Het programma hangt in een eindeloze while-lus:
- De conditie in een while-lus is fout.
- De body van een while-lus bevat geen opdracht die
de "voortgang" stuurt, zoals n = n - 1
bij while n != 0 :
- Het programma hangt in een eindeloze recursie:
een routine die zichzelf (eventueel indirect) telkens weer aanroept.
- Het programma wacht op invoer, zonder dit te hebben aangekondigd.
Copyright © 2004,
Tom Verhoeff
Validate HTML