Unit testen: controleren van aanroepen binnen een klasse
Inleiding tot unit testing met googlemock
Dit artikel behandelt een specifiek probleem bij het unit testen met **GoogleMock**: hoe kan je controleren of een methode van een klasse is aangeroepen vanuit een andere methode binnen dezelfde klasse? Het doel is om Foo::runMe() aan te roepen en te verifiëren of Foo::mockMe() met specifieke parameters is aangeroepen. Dit is cruciaal voor het testen van interacties tussen methoden in je code.
Het probleem met mocking
Wanneer je een **MockFoo** object aanmaakt en runMe() aanroept, zal de methode niet draaien omdat deze gemocked is. Het stellen van een verwachting dat mockMe() wordt aangeroepen zal hierdoor falen. Dit komt doordat de gemockte methode de oorspronkelijke implementatie omzeilt. Het is belangrijk om te begrijpen dat mocking bedoeld is om afhankelijkheden te isoleren, niet om de interne werking van de klasse te vervangen, tenzij dat specifiek het doel is.
De oorspronkelijke klasse en mock klasse
De basisstructuur van de klasse ziet er als volgt uit. De abstracte klasse Foo definieert de methoden runMe() en mockMe(). De **MockFoo** klasse erft van Foo en gebruikt MOCK_METHOD macro's om de methoden te mocken. Het is belangrijk dat runMe() en mockMe() virtueel zijn, zodat de mock implementatie kan worden gebruikt.
De oplossing: een 'realrunme()' methode
Een mogelijke oplossing is het toevoegen van een extra methode, realRunMe(), aan **MockFoo**. Deze methode roept de Foo::runMe() methode aan van de parent klasse. Door realRunMe() aan te roepen in de test, wordt de daadwerkelijke Foo::runMe() methode uitgevoerd, wat op zijn beurt de virtuele mockMe() methode in **MockFoo** aanroept, waardoor je de verwachtingen kunt verifiëren.
De verbeterde test code
De test code wordt dan aangepast om realRunMe() aan te roepen in plaats van runMe(). Dit zorgt ervoor dat de keten van aanroepen correct wordt uitgevoerd. De EXPECT_CALL macro wordt gebruikt om te verifiëren dat mockMe() één keer wordt aangeroepen met de waarde true. Dit demonstreert hoe je de interne werking van een klasse kunt controleren tijdens unit testen.
Alternatieve aanpak: on_call
Er is een alternatieve aanpak met ON_CALL(… Invoke …), maar dit vereist nog steeds toegang tot het **Foo** object binnen de **MockFoo** klasse. De overhead lijkt vergelijkbaar, maar de oplossing met realRunMe() wordt als meer direct en overzichtelijk beschouwd. Het belangrijkste is om een methode te vinden die je testcode leesbaar en onderhoudbaar houdt.
