Objectgerichte programma’s testen en refactoren · oefening
Lees fouten en herken koppeling
Run tests meldt vier verschillende dingen en ze uit elkaar houden bespaart tijd.
Passed. Geslaagd. Niets te doen.
Failed. Mislukt. Een assertie was onwaar. Het gedrag is niet wat de test zei dat het moest zijn en het rapport noemt de test, het bestand, de regel en je bericht. Dit is het nuttige soort: de machine vertelt je iets specifieks over je programma.
Error. Een fout. De test gooide iets op dat geen assertie was. Een TypeError, een AttributeError, een naam die niet bestaat. De test begon, maar kon niet normaal eindigen. De oorzaak kan in de voorbereiding of in de applicatie zitten: een rapport dat bij een lege quiz door nul deelt is een applicatiefout. Lees de traceback om de bewerking te vinden die de exceptie opgooide voordat je beslist wat je moet herstellen.
Collection error. Een fout bij het verzamelen. Een heel bestand kon niet worden geladen: een syntaxisfout of een import van iets dat er niet is. Niets in dat bestand is uitgevoerd. Herstel dit eerst, omdat de tests in dat bestand tot die tijd slagen noch falen.
De werkvolgorde volgt daaruit: eerst fouten bij het verzamelen, dan uitvoeringsfouten, dan mislukte asserties. Eén ontbrekende import kan een pagina alarmerende uitvoer opleveren die in één keer verdwijnt.
Lees het bericht vóór de traceback
Een mislukking ziet er ongeveer zo uit:
test_a_four_out_of_five_attempt_is_a_b
test_grades.py, line 14
AssertionError: expected Grade: B, got Grade: C
De laatste regel vertelt wat er gebeurde. Het regelnummer zegt waar je moet kijken. De traceback erboven, als die er is, vertelt hoe de uitvoering daar kwam en is vooral nuttig als het om een uitvoeringsfout gaat in plaats van een mislukte assertie.
Daarom stond les 5 op een bericht in een lustest. Alleen AssertionError stuurt je terug om de test te lezen. expected Grade: B, got Grade: C betekent vaak dat dat niet hoeft.
Als een test moeilijk te schrijven is, vertelt de code je iets
Dit is de tweede helft van de les en het is een ontwerpidee in plaats van een testidee.
Om te controleren dat een poging met 4 van de 5 punten een B krijgt, moet je een quiz bouwen, vragen bedenken waarvan de punten optellen tot 5 en waarvan 4 haalbaar zijn, ze toevoegen, een poging maken, sommige goed en andere fout beantwoorden, daarna het rapport aanroepen en naar de tweede regel kijken.
Zes of zeven regels voorbereiding om één string te controleren, en het meeste gaat helemaal niet over letterbeoordelingen. Het gaat over de getallen 4 en 5 op hun plek krijgen via een keten van objecten.
Vergelijk dat met waar de beoordelingsregel echt van afhangt: een score en een totaal. Twee getallen. Al het andere in die voorbereiding bestaat omdat je de beoordelingsregel alleen via een volledig samengestelde Attempt kunt bereiken.
Dat verschil heeft een naam. De beoordelingsregel is gekoppeld aan Quiz, Question en Attempt, hoewel het idee dat die uitdrukt geen van die klassen nodig heeft.
Een test heeft acht regels voorbereiding nodig om één korte string te controleren. Wat is de nuttigste conclusie?
Moeite is een aanwijzing, geen bewijs
Wees voorzichtig met dit idee, want je past het makkelijk te breed toe.
Sommige voorbereiding is terecht. Les 4 bereidde een quiz en een poging voor om report_lines te testen, en dat was juist: het geteste gedrag ging echt over de samenwerking van die objecten.
Het signaal is niet ‘deze test heeft voorbereiding’. Het is voorbereiding die niets te maken heeft met wat je controleert. Vragen en antwoorden horen niet bij het idee ‘80% is een B’. Als ze toch in de voorbereiding verschijnen, zijn ze er om aan de codestructuur te voldoen in plaats van aan de betekenis van het gedrag.
Merk het op, schrijf de test toch en laat die het probleem vastleggen. Les 9 doet er iets aan.
Opdracht
Schrijf test_grades.py en controleer de beoordelingsregel in twee categorieën die de hoofdstukquiz niet kan bereiken.
Importeer wat je nodig hebt en schrijf daarna drie tests:
test_a_four_out_of_five_attempt_is_a_b: bouw een quiz van 5 punten waarin de cursist precies 4 kan scoren, beantwoord de vragen zo en controleer datreport_lines(attempt)[1]"Grade: B"is.test_a_seven_out_of_ten_attempt_is_a_c: hetzelfde voor 7 van de 10 en"Grade: C".test_the_letter_alone_needs_no_quiz: controleer datgrade_letter(0.8)"B"is engrade_letter(0.7)"C", zonder quiz, vraag of poging in de test.
Schrijf de eerste twee via de echte route, door het rapport. Merk op hoeveel van de voorbereiding gaat over de beoordelingsregel bereiken in plaats van over beoordelingen. De derde test doet dezelfde bewering zonder dat alles en wijkt bewust af: die kost bijna niets om te schrijven en bewijst niets over het rapport.