0%

Objectgerichte programma’s testen en refactoren · eindproject

Eindproject: Project: test en refactor de quizapplicatie

Acht lessen met tests en nu de reden ervoor.

Refactoring betekent veranderen hoe code is ingedeeld zonder te veranderen wat die doet. De definitie is eenvoudig. Wat het in de praktijk mogelijk maakt is kunnen bepalen of je de tweede helft van de afspraak hebt nageleefd. Daarvoor dienen je testbestanden.

Je hebt ruim twintig tests voor Question, Quiz, Attempt, de scorefuncties, het rapport en de twee weigeringen. Samen beschrijven ze het meeste van wat deze applicatie belooft. Dat is het vangnet. Nu mag je er bewust in vallen.

Het probleem opnieuw verwoord

De vorige les vond het. De beoordelingsregel is een idee over twee getallen:

een score ten opzichte van een totaal komt overeen met een letter

Maar je kunt die alleen bereiken via een Attempt die een Quiz vol Question-objecten kent. ‘4 van de 5 is een B’ testen kostte zeven regels voorbereiding en zes daarvan gingen over de getallen 4 en 5 op de juiste plek krijgen.

Kijk wat report_lines met het argument doet:

def report_lines(attempt):
    fraction = percentage(attempt.score, attempt.quiz.total_points)
    return [
        f"{attempt.learner}: {attempt.score} of {attempt.quiz.total_points}",
        f"Grade: {grade_letter(fraction)}",
    ]

De functie haalt drie waarden uit de poging en noemt die daarna nooit meer. Alles na dat eerste uitpakken is strings bouwen met een cursistnaam en twee getallen.

De stap: beslissen scheiden van ophalen

Geef elke regel een functie die ontvangt wat die nodig heeft en laat report_lines het deel zijn dat weet waar die waarden staan:

def grade_line(score, total):
    return f"Grade: {grade_letter(percentage(score, total))}"

Nu beantwoordt grade_line(4, 5) de vraag uit de vorige les rechtstreeks, in één regel, zonder quiz. report_lines behoudt de taak: weten dat een score uit attempt.score komt en een totaal uit attempt.quiz.total_points, en de regels in de juiste volgorde zetten.

Dit is het idee over verantwoordelijkheden uit hoofdstuk 6, vanuit een andere richting. Daar was het een ontwerpargument. Hier hebben de tests het voor je gevonden.

De regels van de verplaatsing

Verander het gedrag niet. Niet de formulering, niet de volgorde, niet de spaties. report_lines moet precies teruggeven wat het eerder teruggaf.

Blijf de tests de hele tijd uitvoeren. Niet één keer aan het einde. Na elke stap, zodat een mislukking de stap aanwijst die die veroorzaakte.

Raak de tests niet aan. Het vangnet werkt alleen als het vaststaat terwijl jij beweegt. Een test aanpassen aan nieuwe uitvoer verandert een ontdekte fout in een beslissing die je ongemerkt nam.

Die laatste regel heeft één uitzondering en die heb je vandaag niet nodig: wanneer de gedragswijziging het doel is. Dan verander je eerst bewust de test en kijk je hoe die faalt voordat je die laat slagen.

Halverwege de refactoring faalt test_an_empty_quiz_still_reports. Wat is de juiste reactie?

Wat je bouwt

report.py krijgt uiteindelijk vier functies in plaats van twee.

headline(quiz) blijft precies zoals die is.

score_line(learner, score, total) geeft de eerste regel terug: de cursist en daarna de score ten opzichte van het totaal.

grade_line(score, total) geeft de tweede terug: het woord Grade: en de letter, waarbij onderweg de verhouding wordt berekend.

report_lines(attempt) leest de drie waarden van de poging en geeft de twee regels op volgorde terug door de andere twee functies aan te roepen.

Als je klaar bent, hoort report_lines helemaal geen f-strings te bevatten. Dat is het teken dat de opmaak is verplaatst en alleen het ophalen is achtergebleven.

Opdracht

Refactor report.py zodat de twee rapportregels zonder een Attempt kunnen worden gebouwd.

Houd headline(quiz) precies zoals die is en voeg twee functies toe:

  • score_line(learner, score, total) geeft "Mina: 2 of 5" terug voor ("Mina", 2, 5).

  • grade_line(score, total) geeft "Grade: F" terug voor (2, 5) en berekent zelf de verhouding.

Herschrijf daarna report_lines(attempt) zodat die learner, score en total_points van de poging leest en de twee regels teruggeeft door die functies aan te roepen. Als je klaar bent, hoort die geen f-strings te bevatten.

Niets wat het programma afdrukt mag veranderen. Gebruik Run tests tussendoor: al je testbestanden uit dit hoofdstuk moeten groen blijven en geen ervan mag worden bewerkt.