GoogleMock: Een methode testen en een andere mocken binnen dezelfde klasse
Het probleem: testen van methoden die andere methoden aanroepen
Soms wil je in je unit tests controleren of een methode binnen een klasse een andere methode van dezelfde klasse heeft aangeroepen. Stel, je wilt Foo::runMe() aanroepen en vervolgens verifiëren of Foo::mockMe() met specifieke parameters is aangeroepen. Dit is een veelvoorkomend scenario bij het testen van complexe interacties binnen objecten. De uitdaging zit hem in het feit dat het mocken van methoden, zoals gedaan met **GoogleMock**, de oorspronkelijke implementatie overschrijft, waardoor de test direct faalt als je verwachtingen stelt.
De originele code en het mocken
Laten we eens kijken naar de klassestructuur. De basisklasse Foo heeft virtuele methoden runMe() en mockMe(). De mockklasse MockFoo erft van Foo en gebruikt MOCK_METHOD om de methoden te mocken. Wanneer je nu een MockFoo object aanmaakt en runMe() aanroept, wordt de gemockte versie uitgevoerd. Als je verwacht dat mockMe() wordt aangeroepen, zal de test falen, omdat runMe() niets doet anders dan gemocked te zijn.
Een oplossing: realrunme() toevoegen
Een mogelijke oplossing is het toevoegen van een extra methode, bijvoorbeeld realRunMe(), aan de MockFoo klasse. Deze methode roept de virtuele methode runMe() aan van de basisklasse Foo. Dit zorgt ervoor dat de originele implementatie van runMe() wordt uitgevoerd. Daarna wordt automatisch mockMe() aangeroepen, omdat het virtueel is. Dit stelt je in staat om je verwachtingen te verifiëren.
Voorbeeld code met realrunme()
Hier is een voorbeeld van de code: De MockFoo klasse bevat nu MOCK_METHOD0(runMe, void()), MOCK_METHOD1(mockMe, int(bool)) en void realRunMe() {Foo::runMe();}. In de testcode roep je dan foo.realRunMe() aan. Dit zorgt ervoor dat Foo::runMe() wordt uitgevoerd, wat vervolgens MockFoo::mockMe() aanroept, waardoor je je verwachtingen kunt controleren met EXPECT_CALL.
Alternatieve aanpak: on_call
Een alternatieve benadering zou kunnen zijn om ON_CALL te gebruiken om de aanroep van mockMe() te configureren. Echter, dit zou nog steeds vereisen dat deze configuratie plaatsvindt binnen de MockFoo klasse zelf, om toegang te hebben tot de basisklasse Foo. De overhead lijkt vergelijkbaar met de realRunMe() methode, maar de eerste oplossing wordt over het algemeen als directer ervaren.
Conclusie: het kiezen van de juiste strategie
Het mocken van methoden en het testen van hun interacties vereist zorgvuldige planning. De realRunMe() methode, door de originele implementatie aan te roepen, biedt een relatief eenvoudige en overzichtelijke oplossing voor het testen van methoden die andere methoden binnen dezelfde klasse aanroepen met **GoogleMock**. Kies de oplossing die het beste past bij de complexiteit van je code en je testdoelen.
