Equivalentiepartitionering: Testontwerptechniek uitgelegd met uitgewerkte voorbeelden
Je kunt niet elke mogelijke invoer testen, dus welke waarden moet je kiezen? Equivalentiepartitionering geeft u een duidelijk antwoord. Leer de methode stap voor stap, werk door echte voorbeelden en kijk waar er hulp nodig is.
- Equivalentiepartitionering verdeelt invoer in groepen die zich op dezelfde manier moeten gedragen.
- U test één representatieve waarde uit elke groep in plaats van elke waarde.
- Voeg altijd ongeldige partities toe, omdat foutafhandeling de plek is waar veel bugs zich verbergen.
- Het werkt het beste naast grenswaardeanalyse, omdat bugs zich vaak aan de randen van een groep bevinden.
Een leeftijdsveld dat 18 tot 60 jaar accepteert, heeft een enorm aantal mogelijke invoermogelijkheden, zodra je negatieven, grote getallen, tekst en spaties telt. Niemand kan ze allemaal proberen. Equivalentiepartitionering lost dit op door invoer te groeperen die de software op dezelfde manier moet behandelen, en vervolgens één waarde uit elke groep te testen.
Het is een van de eerste testontwerptechnieken die elke tester zou moeten leren. In deze handleiding werken we er stap voor stap doorheen en testen we één voorbeeld in Python. We hebben die code uitgevoerd op Python 3.13 en de uitvoer ervan is inbegrepen. De onderstaande wachtwoord- en couponregels zijn illustratieve voorbeelden en niet afkomstig van een echt systeem.
Wat is equivalentiepartitionering?
Equivalentiepartitionering, ook wel equivalentieklassepartitionering (ECP) genoemd, is een black box-testontwerptechniek. Het verdeelt de mogelijke invoer van een feature in partities of klassen. Er wordt verwacht dat elke waarde binnen een partitie hetzelfde soort gedrag produceert.
Omdat u de code niet hoeft te zien, kunt u deze vanuit een vereiste direct toepassen. Lees voor meer informatie over deze manier van testen black box- versus white box-testen.
Waarom het werkt
De techniek berust op één aanname: als één waarde in een partitie een bug vindt, zullen de anderen in die partitie deze waarschijnlijk ook vinden. En als één waarde slaagt, zullen de andere waarschijnlijk ook slagen. Het testen van 25, 26 en 27 op volwassen leeftijd zal u waarschijnlijk niets vertellen wat het testen van 25 alleen niet deed.
| Benadering | Tests voor een leeftijdsveld | Resultaat |
|---|---|---|
| Uitputtend | Elke mogelijke waarde | In de praktijk onmogelijk |
| Willekeurig raden | Wat er ook in je opkomt | Dubbelen en gaten |
| Equivalentiepartitionering | Eén per partitie | Klein, met bewuste dekking |
Het is echter een aanname en geen garantie. Software kan speciale gevallen verborgen hebben binnen een partitie, een beperking waar we later op terugkomen.
Zo doe je dat in vijf stappen
- Lees de vereiste en identificeer de invoer en de bijbehorende regels.
- Zoek de geldige partities, dit zijn de groepen waarden die moeten worden geaccepteerd, en kijk of verschillende bereiken zich verschillend gedragen.
- Zoek de ongeldige partities, inclusief waarden die te laag, te hoog, het verkeerde type en blanco zijn.
- Kies één representatieve waarde uit elke partitie, meestal ergens in het midden.
- Schrijf voor elk het verwachte resultaat op, zoals bij elke goede testcase.
Uitgewerkt voorbeeld: een leeftijdsveld
Vereiste: Gebruikers van 18 tot 60 jaar kunnen zich registreren.
| Partitie | Typ | Testwaarde | Verwacht resultaat |
|---|---|---|---|
| Onder de 18 | Ongeldig | 10 | Afgewezen |
| 18 tot 60 | Geldig | 35 | Geaccepteerd |
| Boven de 60 | Ongeldig | 75 | Afgewezen |
| Geen nummer | Ongeldig | “abc” | Fout |
| Leeg | Ongeldig | (empty) | Bericht “Vereist”. |
Vijf tests geven u dekking voor elk gedrag in de vereiste. Veel tutorials stoppen bij de eerste drie rijen, maar de laatste twee zijn degene die echte gebruikers per ongeluk activeren. U kunt ook rijen voor negatieve getallen of decimalen toevoegen, als deze redelijkerwijs anders kunnen worden verwerkt.
Het testen in code
Hier is die regel als een functie, met één eenheidstest per partitie, met behulp van de ingebouwde unittest van Python:
import unittest
def can_register(age):
if not isinstance(age, int) or isinstance(age, bool):
raise TypeError("age must be a whole number")
return 18 <= age <= 60
class EquivalenceTests(unittest.TestCase):
def test_valid_partition(self):
self.assertTrue(can_register(35))
def test_too_young_partition(self):
self.assertFalse(can_register(10))
def test_too_old_partition(self):
self.assertFalse(can_register(75))
def test_wrong_type_partition(self):
with self.assertRaises(TypeError):
can_register("abc")
Onze run ging voorbij:
test_too_old_partition ... ok
test_too_young_partition ... ok
test_valid_partition ... ok
test_wrong_type_partition ... ok
In een echt project is de parametrize-functie van pytest een handige manier om een tabel met partitiewaarden door één enkele test te laten lopen.
Uitgewerkt voorbeeld: een wachtwoord
Vereiste: Een wachtwoord moet 8 tot 20 tekens lang zijn en minimaal één cijfer bevatten.
Deze heeft twee regels, lengte en inhoud, dus we overwegen partities voor beide:
| Partitie | Typ | Testwaarde | Verwacht resultaat |
|---|---|---|---|
| Geldige lengte, bevat een cijfer | Geldig | zonsopgang42 |
Geaccepteerd |
| Te kort | Ongeldig | abc1 |
Fout: te kort |
| Te lang | Ongeldig | Een waarde van 30 tekens met een cijfer | Fout: te lang |
| Geldige lengte, geen cijfer | Ongeldig | zonsopgangdag |
Fout: cijfer nodig |
| Leeg | Ongeldig | (empty) | Fout: vereist |
Houd er rekening mee dat elke ongeldige test slechts één regel overtreedt. Als een waarde zowel te kort was als een cijfer miste, kon een geslaagde test u niet vertellen welke controle werkte. De ene cheque kan worden verbroken, terwijl de andere het feit verbergt.
Uitgewerkt voorbeeld: niet-numerieke invoer
De techniek is niet beperkt tot nummerreeksen. Discrete opties, categorieën en statussen vormen ook partities. Stel dat een winkel deze regel heeft:
Vereiste: De bezorging is gratis voor Gold-leden, 50 voor Silver en 100 voor alle anderen. Onbekende niveauwaarden zijn fouten.
| Partitie | Testwaarde | Verwachte vergoeding |
|---|---|---|
| Goud | goud |
0 |
| Zilver | zilver |
50 |
| Geen lidmaatschap | (none) | 100 |
| Onbekend niveau | platina |
Fout |
Hier is elke optie zijn eigen partitie, omdat elke optie zich anders zou moeten gedragen. Andere veel voorkomende partities zijn bestandstypen, zoals geldige en ongeldige uploads, en op uitvoer gebaseerde groepen, zoals een lening die wordt goedgekeurd of geweigerd.
Tip: Denk zowel aan de uitgangen als aan de ingangen. Als een berekening een korting, geen korting of een waarschuwing kan opleveren, zorg er dan voor dat ten minste één test elk van deze uitkomsten bereikt.
Meerdere ingangen tegelijk
Met meerdere velden groeit het aantal combinaties snel. Drie velden met elk vier partities geven 64 combinaties. Twee strategieën helpen:
- Zwakke dekking: zorg ervoor dat elke partitie in ten minste één test voorkomt, waarbij verschillende geldige waarden per test worden gecombineerd. Voor ongeldige waarden test u één voor één, zodat fouten elkaar niet maskeren.
- Op regels gebaseerde dekking: wanneer combinaties het resultaat daadwerkelijk veranderen, zoals de ledenstatus met de bestelwaarde, gebruik dan testen van de beslissingstabel om ze correct weer te geven.
Koppeling met grenswaardeanalyse
Partitioneren vertelt u welke groepen u moet testen. Het zegt weinig over waar in een groep insecten zich graag verstoppen, en velen verstoppen zich aan de randen. Om dit te laten zien, hebben we een versie met fouten geschreven met de klassieke ‘off-by-one’-fout:
def buggy(age):
return 18 < age <= 60 # should be 18 <= age
[buggy(a) for a in (35, 10, 75)] # [True, False, False]
buggy(18) # False
Onze partitiewaarden, 35, 10 en 75, gaven allemaal de juiste antwoorden, dus die tests zouden slagen. Toch wordt een 18-jarige ten onrechte afgewezen. Dit is de reden waarom de twee technieken bij elkaar horen:
| Techniek | Kiest | Waarden voor de leeftijd van 18 tot 60 jaar |
|---|---|---|
| Equivalentiepartitionering | Eén waarde binnen elke groep | 10, 35, 75 |
| Grenswaardeanalyse | Waarden aan de randen van elke groep | 17, 18, 60, 61 |
Gebruik partities om de groepen te vinden, en vervolgens grenzen om te testen waar groepen samenkomen. In onze code gaf een aparte test voor 17, 18, 60 en 61 de juiste functie door en zou die bug onderscheppen. Onze gids voor grenswaardeanalyse behandelt dit volledig.
Voordelen en beperkingen
| Voordelen | Beperkingen |
|---|---|
| Vermindert het aantal tests aanzienlijk | Vertrouwt erop dat partities correct zijn |
| Geeft duidelijke, verklaarbare dekking | Kan bugs bij grenzen missen |
| Heeft geen toegang tot de code nodig | Kan verborgen speciale gevallen missen |
| Vroeg van toepassing, zelfs vanuit vereisten | Modelleert reeksen of combinaties niet goed |
Het grootste risico is een onjuiste aanname. Als de code een verborgen regel voor één specifieke waarde bevat, kan de door u gekozen test deze eenvoudigweg niet bereiken. Verkennende tests en codedekking helpen je te ontdekken wat de partities hebben gemist.
Veel voorkomende fouten
- Ongeldige partities vergeten. Als u alleen gelukkige paden test, wordt de foutafhandeling uitgeschakeld.
- Verschillende waarden testen vanaf één partitie. Dit brengt kosten met zich mee zonder nieuwe informatie.
- Het combineren van meerdere ongeldige waarden in één test. De ene fout kan de andere verbergen.
- Grenzen overslaan. Partitietests alleen al missen vaak off-by-one-bugs.
- De regels raden. Als een vereiste onduidelijk is, vraag het dan. Moeten 60 ook mensen omvatten die 60 en een half jaar oud zijn?
Tot slot
Equivalentiepartitionering vervangt “hoeveel tests moet ik schrijven?” met een veel betere vraag: “welke gedragingen bestaan er, en heb ik ze allemaal besproken?” Om het te proberen, neemt u een formulier dat u vandaag aan het testen bent en vermeldt u de partities ervan op papier, inclusief de ongeldige partities. Voeg vervolgens grenzen toe. Je zult vaak eindigen met minder tests die meer bugs vinden.
Veelgestelde vragen
Wat is equivalentiepartitionering bij testen?
Het is een black box-techniek die input verdeelt in groepen die zich naar verwachting hetzelfde zullen gedragen. Vervolgens test je uit elke groep één representatieve waarde, niet elke waarde.
Wat is het verschil tussen equivalentiepartitionering en grenswaardeanalyse?
Bij het partitioneren wordt één waarde uit elke groep gekozen. Grenswaardeanalyse test de waarden aan de randen van die groepen. Ze worden meestal samen gebruikt.
Hoeveel testgevallen zijn er nodig voor equivalentiepartitionering?
Meestal minstens één per partitie, zowel geldig als ongeldig. Een veld voor een leeftijdscategorie heeft doorgaans ongeveer drie tot vijf tests nodig.
Is gelijkwaardigheid een black box of een white box?
Het is een black box-techniek, omdat partities voortkomen uit vereisten en de code niet nodig hebben. Ontwikkelaars kunnen het echter ook toepassen op unit-tests.
Wat zijn geldige en ongeldige partities?
Geldige partities bevatten waarden die het systeem zou moeten accepteren. Ongeldige partities bevatten waarden die moeten worden afgewezen, zoals getallen die buiten het bereik vallen, verkeerde typen en spaties.
Blijf leren
Hulp nodig met testen, WordPress of SEO?
We helpen teams betere software te leveren en hun sites te laten groeien. Vertel ons waar u mee bezig bent en wij stellen een duidelijke volgende stap voor.
Meer handleidingen over testen, AI en moderne ontwikkeling
Genoten van dit artikel? Kies een onderwerp en ga direct naar onze nieuwste tutorials.
AI-hallucinaties uitgelegd: waarom taalmodellen dingen verzinnen en hoe ze te verminderen
AI-hallucinaties uitgelegd: wat ze zijn, waarom taalmodellen ze produceren, veelvoorkomende typen, hoe je ze kunt verminderen met aarding en aanwijz…
Lees artikel →DevOpsOmgevingsvariabelen uitgelegd: .env-bestanden, geheimen en configuratie goed gedaan
Omgevingsvariabelen uitgelegd met Python-voorbeelden die we hebben uitgevoerd: ze lezen en instellen, waarom elke waarde een string is, .env-bestand…
Lees artikel →SoftwareontwikkelingAPI-snelheidsbeperking uitgelegd: algoritmen, headers en afhandeling van 429-fouten
API-snelheidsbeperking uitgelegd met een simulatie die we hebben uitgevoerd: token-bucket, vast venster, schuifvenster, 429 reacties, headers van sn…
Lees artikel →TestautomatiseringSpotten in Python: unittest.mock, patch en de fouten die tests doen liegen
Spotten in Python met unittest.mock, getest: Mock en return_value, side_effect, patchen waar een naam wordt gebruikt, spec en autospec, spotdatums e…
Lees artikel →SoftwaretestenCodedekking uitgelegd: lijn versus filiaaldekking en wat 100% werkelijk betekent
Codedekking uitgelegd met een echte dekking.py-run: dekking van lijnen, vertakkingen en condities, een rapport lezen, waarom 100% dekking nog steeds…
Lees artikel →Databases & SQLDELETE versus TRUNCATE versus DROP in SQL: verschillen, terugdraaien en wanneer elk te gebruiken
DELETE versus TRUNCATE versus DROP uitgelegd met geteste SQL: wat elk verwijdert, terugdraaien, triggers, identiteitsreset, snelheid en hoe PostgreS…
Lees artikel →Databases & SQLSQL-weergaven uitgelegd: creëer, gebruik en vermijd de valkuilen, met voorbeelden
SQL-weergaven uitgelegd met query's die we hebben uitgevoerd: een weergave maken, live resultaten, kolommen verbergen, prestaties, bijwerkbare en ge…
Lees artikel →SoftwareontwikkelingTypeScript-interface versus type: echte verschillen, getest met de compiler
TypeScript-interface versus type, gecontroleerd met de echte compiler: wat beide kunnen doen, wat slechts één kan doen, samenvoegen van declaraties,…
Lees artikel →SoftwareontwikkelingPython *args en **kwargs uitgelegd: flexibele functies met duidelijke voorbeelden
Python *args en **kwargs uitgelegd met code die we hebben uitgevoerd: in- en uitpakken, parametervolgorde, argumenten die alleen trefwoorden en posi…
Lees artikel →SoftwareontwikkelingPython Lambda-functies: syntaxis, echt gebruik en wanneer u ze niet moet gebruiken
Python lambda-functies uitgelegd met code die we hebben uitgevoerd: syntaxis, sorteren met sleutel, kaart en filter, sluitingen, de laat-bindende va…
Lees artikel →Kunstmatige intelligentieWat zijn AI-agenten? Hoe ze werken, met een eenvoudige agentloop die u kunt uitvoeren
Wat zijn AI-agenten? Een duidelijke gids voor de agentenlus, tools, geheugen en vangrails, met een kleine Python-lus die we hebben uitgevoerd, echte…
Lees artikel →DevOpsMonitoring versus waarneembaarheid: het echte verschil, met logboeken, statistieken en sporen
Monitoring versus waarneembaarheid uitgelegd: bekende en onbekende fouten, logboeken, statistieken en sporen, een walkthrough voor afrekenincidenten…
Lees artikel →DevOpsDocker-volumes versus bindingsmounts: bewaar containergegevens op de juiste manier
Docker-volumes versus bind-mounts uitgelegd: waarom containergegevens verdwijnen, benoemde volumes, bind-mounts, tmpfs, Compose-voorbeelden, back-up…
Lees artikel →TestautomatiseringTDD versus BDD: belangrijkste verschillen, één functie die op beide manieren is gebouwd en wanneer deze moet worden gebruikt
TDD versus BDD uitgelegd met één kortingsfunctie die in beide richtingen is gebouwd: rood-groen-refactor met code die we hebben uitgevoerd, gegeven-…
Lees artikel →SoftwaretestenGebruikersacceptatietesten (UAT): proces, checklist en echte voorbeelden
Gebruikersacceptatietesten uitgelegd: wie voert het uit, hoe het verschilt van QA, een proces in zeven stappen, een UAT-testcase-sjabloon, een check…
Lees artikel →Databases & SQLSQL NULL-waarden uitgelegd: IS NULL, COALESCE, NULLIF en de te vermijden vallen
SQL NULL-waarden uitgelegd met query's die we hebben uitgevoerd: logica met drie waarden, IS NULL, COALESCE, NULLIF, hoe aggregaten, joins en sorter…
Lees artikel →Databases & SQLSQL CASE WHEN-instructie: syntaxis, echte voorbeelden en veelvoorkomende fouten
SQL CASE WHEN uitgelegd met vragen die we hebben uitgevoerd: eenvoudige en doorzochte formulieren, volgorde van de voorwaarden, draaipunten met SUM,…
Lees artikel →SoftwareontwikkelingWat is JWT? JSON-webtokens uitgelegd met een werkend voorbeeld
Wat is JWT? JSON Web Tokens uitgelegd: de drie delen, een token gebouwd en waarmee is geknoeid in de code die we hebben uitgevoerd, JWT versus sessi…
Lees artikel →SoftwareontwikkelingJavaScript-gebeurtenislus uitgelegd: call-stack, microtaken en timers met voorbeelden
De JavaScript-gebeurtenislus uitgelegd met code die we hebben uitgevoerd: call-stack, taak- en microtask-wachtrijen, waarom setTimeout 0 niet onmidd…
Lees artikel →SoftwareontwikkelingPython-generatoren en opbrengst uitgelegd: bespaar geheugen met echte voorbeelden
Python-generatoren en opbrengst uitgelegd met code die we hebben uitgevoerd: hoe ze pauzeren en hervatten, gemeten geheugenbesparingen, pijplijnen, …
Lees artikel →Kunstmatige intelligentieWat zijn inbeddingen? Vectoren en cosinusovereenkomst eenvoudig uitgelegd
Wat zijn insluitingen? Een gids in duidelijke taal over vectoren, cosinusovereenkomst en semantisch zoeken, met een klein voorbeeld dat we hebben ui…
Lees artikel →DevOpsImplementatie van blauwgroen versus kanarie: verschillen, afwegingen en hoe te kiezen
Blauw-groen versus kanarie-implementatie uitgelegd: hoe elk werkt, kosten, risico's en terugdraaien, stabiele gebruikersbucket die we hebben getest,…
Lees artikel →TestautomatiseringSchilferige tests: wat de oorzaak ervan is en hoe u ze voorgoed kunt oplossen
Zwakke tests uitgelegd met demo's die we hebben uitgevoerd: de belangrijkste oorzaken, hoe je er een kunt bevestigen en diagnosticeren, goede oploss…
Lees artikel →SoftwaretestenBelastingtesten versus stresstesten: verschillen, statistieken en k6-voorbeelden
Belastingtesten versus stresstesten uitgelegd: wat elk bewijst, piek- en soak-tests, de statistieken die er toe doen, waarom gemiddelden misleiden, …
Lees artikel →SoftwaretestenTestcase versus testscenario: belangrijkste verschillen, voorbeelden en wanneer deze te gebruiken
Testcase versus testscenario uitgelegd: duidelijke definities, een tabel naast elkaar, één functie voor het opnieuw instellen van wachtwoorden, over…
Lees artikel →Databases & SQLOptimalisatie van SQL-query's: lees uitvoeringsplannen en repareer langzame query's, met timing
Optimalisatie van SQL-query's getest op een miljoen rijen: lees uitvoeringsplannen, voeg de juiste indexen toe, repareer niet-sargeerbare filters, g…
Lees artikel →Databases & SQLSQL UNION versus UNION ALL: verschillen, voorbeelden en geteste prestaties
SQL UNION versus UNION ALL uitgelegd met de query's die we hebben uitgevoerd: duplicaten, de regels volgen beide, een echte databug, gemeten prestat…
Lees artikel →SoftwareontwikkelingJavaScript Fetch API-tutorial: GET, POST, foutafhandeling en time-outs
Een JavaScript Fetch API-tutorial getest tegen een lokale server: GET en POST, waarom 404 niet gooit, een herbruikbare helper, queryreeksen, time-ou…
Lees artikel →SoftwareontwikkelingPython-bestandsverwerking: lezen, schrijven, CSV, JSON en pathlib met voorbeelden
Het verwerken van Python-bestanden uitgelegd met code die we hebben uitgevoerd: open modi, met het lezen van grote bestanden, CSV, JSON, pathlib, bi…
Lees artikel →SoftwareontwikkelingPython-klassen en -objecten: OOP-zelfstudie met echte voorbeelden
Python-klassen en -objecten uitgelegd met code die we hebben uitgevoerd: __init__, methoden, klasse versus instantie-attributen, overerving, eigensc…
Lees artikel →Kunstmatige intelligentieWat is een groot taalmodel? Hoe LLM's werken, uitgelegd zonder de hype
Wat is een groot taalmodel? LLM's uitgelegd in duidelijke taal: tokens, inbedding, aandacht, training, temperatuur- en contextvensters, een kleine d…
Lees artikel →DevOpsLinux-opdrachten voor beginners: de essentiële terminalgids met voorbeelden
Linux-opdrachten voor beginners, gegroepeerd op taak: navigatie, bestanden, logboeken bekijken, grep, pipelines, machtigingen, processen en archieve…
Lees artikel →TestautomatiseringSelenium versus toneelschrijver: belangrijkste verschillen, code vergeleken en welke te kiezen
Selenium versus Playwright vergeleken: architectuur, wachten, browser- en taalondersteuning, debuggen, dezelfde test in beide tools, migratieadvies …
Lees artikel →SoftwaretestenEquivalentiepartitionering: testontwerptechniek uitgelegd met uitgewerkte voorbeelden
Equivalentiepartitionering uitgelegd: hoe je geldige en ongeldige partities kunt vinden, uitgewerkte voorbeelden voor leeftijden, wachtwoorden en ko…
Lees artikel →SoftwaretestenErnst versus prioriteit bij het testen van software: verschillen, matrix en echte voorbeelden
Ernst versus prioriteit bij het testen van software uitgelegd: duidelijke definities, een vierwegmatrix met voorbeelden, niveauschalen, wie deze bep…
Lees artikel →Databases & SQLTutorial voor SQL-subquery's: typen, gecorreleerde subquery's en BESTAAN met voorbeelden
Een SQL-subquery-tutorial met query's die we hebben uitgevoerd: scalaire, IN-, FROM- en SELECT-subquery's, gecorreleerde subquery's, EXISTS, de NOT …
Lees artikel →Databases & SQLSQL-transacties en ACID uitgelegd: COMMIT-, ROLLBACK- en isolatieniveaus
SQL-transacties en ACID uitgelegd met een bankoverschrijving die we hebben uitgevoerd: COMMIT, ROLLBACK, savepoints, locks, isolatieniveaus, dirty r…
Lees artikel →SoftwareontwikkelingGit merge vs rebase: verschillen, voorbeelden en wanneer je wat gebruikt
Git merge vs rebase uitgelegd met echte logoutput, een vergelijkingstabel, de gouden regel van rebase en een veilige teamwerkwijze.
Lees artikel →SoftwareontwikkelingPython list comprehension: syntaxis, voorbeelden en wanneer je het vermijdt
Python list comprehension uitgelegd: syntaxis, filteren, if-else, geneste lussen, gemeten tijden en wanneer een gewone for-lus beter is.
Lees artikel →Databases & SQLSQL JOIN uitgelegd met voorbeelden (Inner, Left, Right, Full)
Begrijp SQL joins stap voor stap met voorbeeldtabellen en queries: INNER, LEFT, RIGHT, FULL, CROSS en SELF, plus veelgemaakte fouten en prestatietips.
Lees artikel →