Niet mocken!

 
09 juni 2008

Het heeft voor mijn gevoel tamelijk lang geduurd, maar unit-testing begint nu langzaam maar zeker normaal te worden in een software-ontwikkeltraject. Zelf kan ik niet meer zonder. Binnen een statisch getypeerde taal is het namelijk één van de weinige mogelijkheden om direct feedback van jouw software te krijgen. Toch lijkt in het huidige gebruik een belangrijk aspect van unit-testen verloren te gaan.

Om voor elke methode en class in je code een test te schrijven lijkt op het eerste gezicht veel werk met slechts beperkt nut. Bij mijn eigen introductie in het unit-testen had ik ook dat gevoel. Na erover nagedacht te hebben en het tijdens een project toegepast te hebben was ik echter om. Ze helpen echt bij het ontwikkelen. Sinds dat project ben ik een trouwe unit-tester.

Helaas zijn niet alle methodes even gemakkelijk te testen. Methodes en classes grijpen soms op complexe wijze in elkaar en hebben afhankelijkheden naar externe resources. Waardoor het vrijwel onmogelijk wordt een goede test te schrijven voor een methode zonder de rest van het programma te gebruiken.

Maar geen nood, zoals gebruikelijk met dit soort problemen in software-ontwikkeling, hebben de knappe koppen een oplossing gevonden in de vorm van een framework. De afhankelijkheden die het testen lastig maken kunnen nu gesimuleerd worden. Dit maakt het mogelijk om de methode die gebruik maakt van al die andere objecten toch te testen. Door mock-versies te maken van die objecten…

De volgende vraag is dan natuurlijk; Welke van deze handige frameworks gebruik IK? Het antwoord is misschien al aan de titel te lezen: Geen! Mocken is namelijk onzin! In al die tijd dat ik unit-tests schrijf heb ik nog nooit een mock-object nodig gehad.

“Ja maar”, roep je nu misschien, “iedereen heeft toch wel methodes die anders niet te testen zijn?”. Dat klopt, maar misschien is het een indicatie van een ander probleem. Dat er een unit-test geschreven wordt voor de methode wil zeggen dat er bepaalde logica in deze methode aanwezig is. Een methode zonder logica heeft namelijk weinig zin om te testen. Dat deze methode te lastig is om te testen wil ook zeggen dat deze methode communiceert met andere objecten of entiteiten. Dus de methode heeft logica en collaboratie. Dit zijn twee aparte taken. Een goede methode hoort echter maar een enkele taak te hebben. Het antwoord is dus niet een mock object introduceren, maar je code refactoren!

Unit-tests testen niet alleen de logica van de software. Ze testen ook de testbaarheid van jouw code. Dit klinkt misschien een beetje dubbel, maar de testbaarheid van je code wordt bepaald door de mate van ontkoppeling en encapsulatie. Met andere woorden, het design van jouw software. Als unit-testen lastig is in jouw applicatie dan is dat niet een reden om mock-objecten te introduceren of misschien maar helemaal niet te te testen. Het is een indicatie dat er fundamentele fouten in het design zitten.

Dit klink misschien een beetje abstract, maar uit eindelijk is het niet zo ingewikkeld. Een situatie die ik vaak tegenkom is bijvoorbeeld deze:

void doSomething(){
data = this.dao.ExcecuteSomeComplexDataFindingArgorithm();
// do something with data
}
Dit is min of meer de structuur die door bepaalde ontwikkelframeworks in de hand gewerkt wordt. Om deze methode te testen moet echter het dao-object aanwezig zijn. Dus kan dit niet getest worden zonder een mock dao object te gebruiken. Er zijn zelfs speciale frameworktechnieken bedacht om het eenvoudig te maken het dao-object te wisselen.

De juist oplossing is echter ontkoppeling. Het dao-object en de ‘do something’ hebben eigenlijk niets met elkaar te maken. Een eenvoudige ontkoppeling is een nieuwe methode te creëren voor onze logica die een argument van het type data ontvangt:

void doSomething(){
data = this.dao.ExcecuteSomeComplexDataFindingArgorithm();
doSomething(data)
}
void doSomething(data){
// do something with data
}
De methode doSomething(data) heeft nu geen afhankelijkheid meer met het dao object en kan eenvoudig getest worden. De methode doSomething zonder argumenten bevat geen eigen logica en hoeft niet getest te worden.

Op deze manier kan volgens mij elk mock-object vermeden worden. Soms is er iets meer nodig. Misschien een nieuwe class of moet de methode naar een ander object verplaatst worden, maar ik wil beweren dat het altijd mogelijk is en je design er altijd beter van wordt.

Misschien zijn er mensen die het niet met me eens zijn. Een enkele keer wil dat wel eens gebeuren. Ik zou deze mensen willen uitnodigen om fragmenten met niet testbare code in de reacties te plaatsten als een tegenvoorbeeld. Aan mij dan om het tegendeel te bewijzen.


Werken met ?
Kijk dan bij onze mogelijkheden voor zowel starters als ervaren engineers.


Categorieën: Architectuur, Development

Tags: , , ,


Reacties (19)

  • Boris van Woerkom schreef:

    Je verhaal nog een keer lezende valt me één groot verschil op bij gebruik van classic vs. mock based testing. Bij classic testing (met refactoring) gebruikt je altijd de state van één of ander object, bij mock testing test je naast state ook gedrag.

    Dit laatste heeft vaak toegevoegde waarde omdat er vaak meerdere wegen leiden naar state == Rome. En hoe kan je bijvoorbeeld een Cache te testen via state based testing? Het refactoren wil je eigenlijk ook pas in een latere iteratie doen pas als de code daar om vraagt.

    Al met al wel een leuke uitdaging om te kijken wat de vroege refactorings voor effect hebben op de coupling en het aantal dependencies op plekken waar ze eigenlijk niet thuishoren.

    Geplaatst op 28 maart 2010 om 0:44 Permalink

    • Ralf Wolter schreef:

      Unittests testen niet zozeer state, dan wel het effect van het gedrag op state. Dat is volgens mij een belangrijk onderscheid.

      Ik ben het met je eens dat een mock framework dit gedrag directer kan testen. Het is echter niet een voordeel in mijn optiek. Zoals je zelf al schetst zijn er meerdere wegen naar Rome en zo ook meerdere manieren om een bepaald effect te bereiken.

      Door te hard op gegrag te testen doorbreken we de encapsulatie van het object en testen we plosteling het “hoe” ipv het “wat”.

      Geplaatst op 30 maart 2010 om 12:26 Permalink

  • Boris van Woerkom schreef:

    Mocking tools bieden mij zeer goede mogelijkheden om geisoleerd nieuwe componenten te kunnen bouwen zonder dat vervelende dependencies (denk aan webservices bij externe partijen / DB / IO / 3rd party systemen) in de weg zitten of er simpelweg (nog) niet zijn.

    Het hele idee achter unit testen is dat je het innerlijk van je “unit” test. Je dependencies mogen daarbij geen rol spelen maar je kan ze er ook niet zo maar uithalen, je zal op een gegeven moment toch willen testen hoe je webservice/facade/etc wordt aangeroepen. Een mocking framework als Moq helpt me daar erg prettig bij. Naast het testen van een begin en eindwaarde kan je hiermee ook testen welke methodes in welke volgorde en hoe vaak etc van de mock zijn aangeroepen.

    Wel mocken!

    Geplaatst op 27 maart 2010 om 3:33 Permalink

    • Ralf Wolter schreef:

      @Boris

      Dat het de bedoeling is dat je met een unit test een enkele unit test en dat afhankelijkheden dat niet mogen blockeren is denk ik iedereen het over eens. De conclusie dat er dan dus gemockd moet worden volgt daar volgens mij echter niet uit.

      Je voorbeeld schetst een situatie waarbij je unit gekoppeld is met andere units. Deze units maken de tests voor de onginele unit onbetrouwbaar. De koppeling met die units is dus een probleem en moet verdwijnen. Tot zo ver zitten we denk wel op een lijn.

      Jou oplossing voor het ontkoppelen is de andere units te vervangen door units die wel betrouwbaar zijn. Je ontkoppelt dus de implementatie of vervangt de units door je Moq units.

      Mijn redenering is een beetje anders. Het feit dat ik de unit los wil kunnen testen van de andere units geeft voor mij aan dat er semantisch gezien een scheiding is tussen deze units. Technisch gezien zijn ze echter gekoppeld. Het is inderdaad lastig te unit testen, maar sterker dan dat het is een overtreding van Dijkstra’s stelling (of is het een vermoeden?) “minimum coupling and maximum cohesion”.

      Het ontwerp van onze units overtreed een van de basis regels van ontwerpen in software systemen. Het is dus een ontwerpfout. Het introduceren van een mock object los de fout in ons ontwerp niet, maar verbergt het alleen. De echte oplossing moet volgens mij zijn dat je de fout in het ontwerp oplost.

      Geplaatst op 27 maart 2010 om 11:14 Permalink

      • Boris van Woerkom schreef:

        Met Dijkstra ben ik het helemaal eens, vooral decoupling is erg belangrijk voor het gecontroleerd laten groeien van een systeem (embrace change). Neemt niet weg dat je altijd te maken hebt met dependencies. Wat ik niet begrijp is dat je zegt dat het gebruik van dependencies een ontwerpfout is. hoe kan software dan met de buitenwereld praten? disk/toetsenbord/scherm/webservices zijn ook dependencies en worden nu eenmaal gebruikt binnen de code. Zelfs wanneer je de dependency via een IoC container in de constructor injecteert zal er ergens in je unit een regel zijn die er gebruik van maakt. Het volledige code pad waarin de dependency gebruikt wordt wil ik testen, waarom zou ik een risico laten bestaan door dit pad niet te testen? bovendien biedt het me de mogelijkheid om situaties te laten ontstaan die normaal erg moeijlijk zijn om na te bootsen (null waarden inschieten, exceptions raizen) en kan ik ook testen hoe het systeem daar op reageert. (meer mensen zouden dat moeten doen).

        De echte oplossing in het ontwerp oplossen? Ik heb geen flauw idee hoe.

        Misschien kan je aan de hand van een voorbeeld aangeven hoe jij een app zou ontwerpen en testen? Neem een app welke als doel heeft om aandelen te kopen en te verkopen. Op basis van een aandelenkoers-webservice en een ingewikkeld algoritme worden beslissingen gemaakt om aan te kopen of van de hand te doen. De opdracht wordt via de webservice van de bank geplaatst.

        ik ga als volgt te werk:

        – maak tests voor ingewikkeld algoritme
        – implementeer algoritme tot tests = groen
        – setup koersmock: IKoersService
        – maak tests waarbij het resultaat vd webservice het algoritme voedt
        – maak tests groen
        – setup bankmock: IBankService
        – maak tests waarbij (mock)koersen worden opgevraagd, algoritme aan de gang gaat en (mock)orders naar de bank stuurt.
        – maak tests groen

        klaar met unit testen, alleen de echte IKoersService en IBankService servicelayers moeten nog gemaakt worden.

        Ik ben nieuwsgierig hoe jij qua ontwerp en test te werk zou gaan.

        Geplaatst op 27 maart 2010 om 21:57 Permalink

        • Ralf Wolter schreef:

          Het is niet zo zeer dat het gebruik van externe afhankelijkheden niet zou, mogen dan dat dat ze geen directe invoed mogen uit oefenen.

          Het aandelen voorbeeld is goed uit te werken volgens zonder afhankelijkheden. Om het voldoende uit te werken vergt meer tijd en ruimte dan in de reacties beschikbaar of wenselijk is denek ik. Het gaat ook dieper in op mijn ideeen rondom object georienterd ontwikkelen en domain driven design dan ik eigenlijk in dit artikel wou gebruiken. Het atrikel probeert juist wat meer puur op unittesten en algemeen design in te gaan.

          Mijn taktiek komt er op neer dat ik eerste een domein model ga ontwerpen. Dit ontwerpen doe ik met een vorm van Exploratory Modelling met unittests. Het resultaat is een werkend domein model zonder externe afhankelijkheden.

          Dit domein model is een complete implementatie van het probleem. Dat wil zeggen alles activiteiten die ondersteunt moeten worden zitten erin. Misschien is het correcter om te zeggen dat het een simulatie is van het probleem.

          Koppelingen met externe diensten vanuit dit domein worden hierna gebouwd. De koppelingen zelf zijn events, dus agnostisch over de ontvanger en veroorzakende functie. Dit maakt een losse koppeling mogelijk die de unit tests zelf niet beinvloed.

          Ik kan me voorstellen dat dit nog tamelijk abstact blijft voor veel mensen. Het is misschien een goed idee om het eens verder uit te werken in een los artikel. Het kan zelfs interessant zijn om de twee methodes eens tegenover elkaar uit te zetten. Zin om samen een dergelijk artikel te schrijven?

          Geplaatst op 30 maart 2010 om 12:17 Permalink

  • Las deze post weer eens en zag mijn veel te lange reactie erop. Duidelijk geval van te weinig tijd eraan besteden en daarmee vergeten het in te korten tot de essentie. Excuses.

    Dan nog een toevoeging: mocking kan natuurlijk ook gebruikt worden voor het simuleren van anders weinig optredend gedrag: willekeurig wegvallen db of netwerk, concurrent calls op hetzelfde object. Dat kan mogelijk ook nog een legitieme reden zijn om te mocken.

    Geplaatst op 08 september 2009 om 21:13 Permalink

  • soemirno schreef:

    @Ralf
    Voor het testen van collaboratie tussen objecten hoef je inderdaad geen mock’s te gebruiken. Je kunt echte objecten gebruiken en het eind resultaat controleren.

    Het gebruik van mock objecten moet je echter niet zien als een noodzaak om iets te testen dat anders niet getest kan worden, maar als een (design) stijl. Als je als basis een CRC card hebt, kun je je class al volledig TDD implementeren, zonder dat de classes van de andere objecten zijn geimplementeerd. Je kunt je object under test hiermee volledig isoleren. Dit principe wordt in Behaviour Driven Development vaak toegepast.

    Mijn ervaring is dat het goed werkt om je ontwerp te sturen, maar minder goed als regressie test, omdat je dan weer apart integratie testen moet maken om met de echte objecten te testen.

    Geplaatst op 29 augustus 2008 om 6:10 Permalink

  • Rick van der Arend schreef:

    @Ralf

    Ik bekijk je post nu even vanuit het oogpunt van iemand die Test Driven Design (TDD) wil toepassen. De hoofdlijn van je verhaal, ‘Niet Mocken’, komt wel overeen met de tendens in TDD: volgens de voorstanders wordt je juist door test driven te ontwerpen, gedwongen om na te denken over een ontwerp waarin je zo weinig mogelijk (vaste) onderlinge afhankelijkheden maakt. Al is het een tendens en wordt er niet altijd een punt van gemaakt om ergens een afhankelijkheid van een ‘vast’ punt in je domein te maken en die dan te mocken en/of te stubben.

    Aan de andere kant gaan er natuurlijk wel alarmbellen rinkelen bij het toestaan van meerdere falende tests, dat is nou juist weer helemaal niet toegestaan. Ook zou ik er niet vanuit gaan dat andere units/objecten aanwezig zijn bij unit testing, dan ben je bezig met integration testing, volgens mij. Ik heb een andere kijk op de zaak.

    Ik zie twee ‘oplossingen’ die het probleem volgens mij samen uit de wereld halen.
    1. Tests (in TDD) dienen om je interface-objecten te testen. Deze objecten zijn volgens mij de entiteiten (van DDD) en units (van unit testing). Objecten (entiteiten/units) die andere objecten gebruiken die achter deze publieke interface liggen, dienen deze zelf aan te maken. Let op, het gaat hier dus om objecten die alleen binnen, ‘achter’ het interface object een betekenis hebben (state, strategy, value objecten, etc). Unit testen van deze aparte objecten zou volgende deze filosofie niet nodig zijn: het relevante gedeelte van hun gedrag wordt al getest via het interfacende object (soms ook entiteit genoemd). Verder is het nog belangrijk om te melden dat deze objecten bij een TDD ontwikkel-manier niet ‘gevraagd’ worden door de tests. Ze ontstaan, tijdens refactoring, puur om het gedrag van het object-onder-test te ondersteunen.

    2. Daar waar in een levend domeinmodel een relatie verwacht wordt met een ander object (anders dan de bovenstaande, dus wel entiteiten/units), kan het ontbreken ervan in een unit test twee type gevolgen hebben:

    2A) Het ontbreken van de relatie is ongewoon, maar geen kritieke toestand. Graceful teruggeven van de controle aan de client (client-object bedoel ik hier) met zoveel mogelijk behoud van functionaliteit als mogelijk. Bijvoorbeeld: de client vraagt om de bij het object-onder-test om een parent object, die er niet is: dan is het object-onder-test dus de root en dient hij zich als zodanig te gedragen. De client krijgt dit als antwoord terug en dient hiermee om te kunnen gaan. De unit-test zou kunnen controleren of dit ook zo gebeurd.

    2B) Het ontbreken van de relatie is een voor de applicatie kritieke toestand. Het object-onder-test dient dan zichzelf in een zo goed mogelijke toestand te houden (dus bijvoorbeeld eventuele roll-back van half gemaakte wijzigingen) en vervolgens een exceptie te gooien. Ook dit is weer iets wat je prima in een unit-test kunt testen. Je weet dat tijdens de unit test (die op 1 unit gebeurt) verwacht mag worden dat de relatie ontbreekt en dus dient het object met de genoemde rollback & exceptie de controle terug te geven aan de client (in dit geval een unit-test dus).

    Is daarmee niet het hele probleem netjes opgelost? Ik ben benieuwd naar jouw visie hierop.

    Overigens, zelfs als je niet van een TDD manier van ontwikkelen houdt, biedt het bovenstaande volgens mij nog genoeg aanknopingspunten om je objecten netjes te unit-testen.

    Geplaatst op 14 augustus 2008 om 20:11 Permalink

  • Ralf Wolter schreef:

    @Soemirno

    Die collaboratie wil je inderdaad graag testen, maar ik vraag me af of je daar een mock object voor nodig hebt.

    Voor objecten die in de zelfde scope of component leven is er volgens mij geen reden om niet het echte collabortie object te gebruiken.

    Scope of component overschreidende collaborties horen eigenlijk niet voor te komen en zouden dus gerefactored moeten worden.

    Geplaatst op 13 augustus 2008 om 16:45 Permalink

  • Ralf Wolter schreef:

    @Jaspers

    Het klinkt inderdaad lastig. Class A en B hebben een circulaire afhankelijkheid. Hoe kan ik nu class A testen zonder eigenlijk ook class B mee te testen?

    Het antwoord is volgens mij tamelijk eenvoudig. Als ik testen aan het schrijven ben voor class A, dan interesseert class B me niet en kan deze genegeerd worden.

    Dat lijkt misschien een flauw antwoord, maar na een diepere blik is het niet zo vreemd. Dat de unit test van A slaagt wil zeggen dat class A voldoet aan de eisen die we eraan stellen. Dit is de basis aanname van test driven development.

    Voor veel mensen volgt hier ook uit dat als de test faalt dat class A niet voldoet aan onze eisen. Logisch gezien is dit echter niet waar. Het falen van onze test zegt niet noodzakelijk iets over het wel of niet voldoen van class A. Testen mogen dus falen terwijl de class wel voldoet aan onze eisen.

    Ik begrijp dat dit in eerste instantie een beetje tegen intuitief lijkt, maar dat komt vooral omdat we nu alleen naar class A kijken. Class B heeft namelijk een eigen test waarvoor het zelde geldt. En in het voorbeeld van een correcte A waarvan de test faalt, moet de test van class B ook falen.

    Het komt er dus op deer dat de testen niet opzich zelf staan. Als alle testen slagen voldoen alle objecten aan de eisen. Indien er meerder testen falen voldoet er ten minste een object niet aan onze eisen.

    Dit gaat er natuurlijk wel vanuit dat onze testen correct en volledig zijn.

    Geplaatst op 13 augustus 2008 om 16:36 Permalink

  • Jasper Stein schreef:

    @Jasper Floor:
    Natuurlijk is het mogelijk dat in de unit tests van je huidige klasse (bv. Auteur) fouten naar boven komen in het gedrag van collaborerende objecten (zoals Boek). Maar als het goed is heb je voor de klasse Boek ook een aantal unit tests geschreven die het Boek-gedrag testen. Bij de unit tests die bij Auteur horen, ga je er dus (lijkt me) vanuit dat de collaborerende Boek-objecten werken zoals ze horen te doen.

    Of die situatie altijd haalbaar is, is natuurlijk de vraag: zodra er een cirkel zit in de samenwerkingsgraaf van objecten (bijv. A gebruikt een B maar B gebruikt op zijn beurt weer een A) wordt het ws. lastig om ze onafhankelijk van elkaar te testen. Ralf, ideeën hierover?

    Geplaatst op 06 augustus 2008 om 23:11 Permalink

  • soemirno schreef:

    Als je een mock framework gebruikt om dure of externe objecten te ‘stubben’, hoef je inderdaad geen mock framework nodig. Maar dat is niet de belangrijkste toepassing van mock frameworks.

    Mock’s zijn handig als je de collaboratie met een ander objecten wilt definieren en valideren. Je gaat dan echt het gedrag met het ander object beschrijven middels het mock framework.

    Het is een andere manier van ontwikkelen, dat door de grote hoeveelheid boilerplate code en de interfaces die je altijd nodig hebt minder populair is in java. Ik vind zelf dat de testen wat moeilijk te lezen zijn dan. In een dynamische taal is het wat beter te doen, omdat je veel minder ruis hebt.

    Geplaatst op 26 juni 2008 om 12:13 Permalink

  • Jasper Floor schreef:

    Wat gebeurt er als in methode doSomething(data) een complex object (class ComplexObject) is wat ook testen verdiend? Op dat moment is er een afhankelijkheid die niet zomaar op deze manier te vermijden is. ComplexObject bevat zelf mischien ook een ander object (class OokComplexObject). Het is niet realistisch om te eisen dat alles naar primitieven wordt vertaald.

    Een simpel voorbeeld is een auteur. Die is waarschijnlijk wel gekoppeld aan een lijst met boeken. Boeken zijn waarschijnlijk ook minimaal een titel en een isbn nummer. Als auteur getest wordt, dan wordt impliciet ook boeken getest. Mischien is het zo dat als een boek forbiddenflag==true wordt opgehaald dat er direkt een bericht verstuurd wordt naar de grote gemene overheid. Als er in die functionaliteit een fout zit dan kan dat naar boven komen als de functie doIetsMetAuters getest wordt.

    Geplaatst op 19 juni 2008 om 12:47 Permalink

  • Ralf Wolter schreef:

    @Jan

    Een leuke vraag en een probleem dat vaak bij unit testen in het algemeen naar voren komt. Hoe moet ik mijn private methodes testen?

    Laat ik eerst de vraag even omdraaien: “Welke methodes worden private?” Uit je reactie maak ik op dat je van mening bent dat niet belangrijke methodes private zijn en belangrijke methodes public.

    Mijn mening hierover is dat methodes die het object in incorrecte state kunnen achterlaten private moeten zijn.

    Het verschil hier is volgens mij dat in het ene geval is private de default en in het andere geval public. Het voordeel van private als default is dat er meestal maar een enkele duidelijke manier is om een object te gebruiken, het nadeel is echter dat het object vaak mee veranderen moet met de consumerende objecten in refactor slagen.

    Bij public als default bewaken we nog steeds de sate en verantwoordelijkheid van het object maar leggen we niet vast hoe het object daadwerkelijk gebruikt moet worden, iets wat de flexibilteit van het object en de applicatie in z’n geheel ten goede komt.

    Als met dit in gedachte naar de twee doSomething methodes kijken dan valt op dat de state manipulatie geheel in het “// do something with data” gedeelte moet zitten. Met public-als-default is er daarom geen reden om de methode doSomething/1 een andere access modifier te geven dan doSomething/0.

    Overigens is het opsplitsten in methodes maar een van de manieren hoe “// do something with data” ontkoppeld kan worden. Vaak is de correcte OO oplossing om het gedrag naar data te trekken. De de methode doSomething/1 wordt data.doSomething(). Deze refactoring maakt doSomething duidelijk een publieke methode van data gezien het van buiten af (door ons object) geconsumeerd wordt.

    Geplaatst op 18 juni 2008 om 10:10 Permalink

  • Jan Hoeve schreef:

    Mijn 2 centen:

    Blijkbaar is de doSomething() methode belangrijk genoeg om van buiten te worden aangeroepen. Deze zal dus public zijn. (Heb je waarschijnlijk weggelaten voor overzichtelijkheid).
    Als je nu de methode splitst in 2-en, komt er een doSomething(data) methode bij, die je wilt kunnen aanroepen vanuit je testclass.
    Dat betekent dat deze methode op zijn minst package-visibility moet hebben. Wanneer je via een interface werkt, moet deze zelfs in de interface gedeclareerd zijn ,waardoor deze public wordt.
    Daardoor worden deze beide doSomething() methodes dus beschikbaar gesteld voor ‘derden’ ter wijl je er maar één beschikbaar wilt geven.

    Ben benieuwd hoe je hier mee omgaat :)

    Geplaatst op 18 juni 2008 om 7:42 Permalink

  • Ralf Wolter schreef:

    @Stefan

    Voor een goede test is het scenario dat getest wordt een vast gegeven. Voor de manipulatie van “data” gelden bepaalde pre en post condities. Al deze condities moeten dus eigenlijk getest worden.

    Dit kan vaak breder zijn dan de daadwerkelijk output van de query methode. Het is daarom inderdaad volgens mij beter om met hard-coded data te werken.

    Geplaatst op 10 juni 2008 om 16:26 Permalink

  • Stefan Bookholt schreef:

    Dit is wel een leuk gegeven. Maar hoe kom je aan het stukje “data” dat je meegeeft aan “doSomething”? Ga je die hard-coderen in je test?

    Geplaatst op 10 juni 2008 om 15:25 Permalink

  • Ralf,

    Helemaal mee eens! Zowiezo een goede zaak om het aantal ‘frameworks’ te minimaliseren en back to basics goed te ontwerpen; dit is hier een heel mooi voorbeeld van.

    Geplaatst op 10 juni 2008 om 7:07 Permalink