mimic++, ein modernes und (fast) Makro-freies Mocking-Framework



  • Hallo,
    über die letzten Wochen und Monate habe ich an einem Projekt gearbeitet, dass ich hier nun kurz vorstellen möchte. Das Framework ist noch nicht ganz production-ready, dennoch wäre es hilfreich ein wenig Feedback zu bekommen.

    Es handelt sich dabei um ein modernes c++20 Mocking-Framework, welches (fast) komplett auf Makros verzichtet.
    Eines meiner Ziele war es, alles über die "reguläre" Sprache abzubilden, was eben möglich ist.

    Ich setze an dieser Stelle voraus, dass ihr in etwa wisst, was Mocking ist. Andernfalls hilft hier eine Suche in der Suchmaschine eures Vertrauens sicherlich weiter (andere beschreiben das sicherlich besser als ich es hier in der Kürze könnte) 🙂

    Ich habe mein Framework mimic++ getauft und habe mich dabei von der generellen Funktionalität vom bekannten trompeloeil Mocking-Framework inspirieren lassen, dass ich nun immerhin auch schon einige Jahre sehr gerne benutzt habe.
    trompeloeil ist sicherlich alles andere als ein schlechtes Framework, besitzt aber auch einige Schwächen und Restriktionen und ist nun leider kaum mehr als "modern" zu betiteln.

    Im Prinzip gibt es zwei Kern Konzepte: Mocks und Expectations.
    Mocks sind die Entitäten, die Verhalten emulieren sollen und mit Expectations versehen werden, die in den entsprechenden Test cases an sie gestellt werden.
    Expectations bieten hierbei eine Vielzahl von Konfigurationsmöglichkeiten (Policies) an:

    • Wie oft sollen sie gematched werden?
    • Welche konkreten Werte sollen die Argumente besitzen?
    • In welcher Reihenfolge sollen mehrere Expectations gematched werden?
    • etc.

    Die Liste ließe sich noch wesentlich weiter fortsetzen und User können sogar relativ einfach eigene Policies kreieren.

    Mocks sind in mimic++ einfache Funktions-Objekte und können daher direkt und ohne Umwege als solche benutzt werden. Es war mir dabei sehr wichtig, möglichst alle Features einer Funktion auch abzubilden. Mocks supporten daher eigentlich alles, was man sich von Funktionen erwartet; selbst overloading ist möglich!

    Als kleines Beispiel:

    mimicpp::Mock<void()> myMock{};
    mimicpp::ScopedExpectation myExpectation = myMock.expect_call();
    myMock();	// consumes myExpectation
    

    Es ist für Nutzer meist nicht sonderlich wichtig, die tatsächlichen Expectation-Objekte zu kennen, daher habe ich hierfür das Makro SCOPED_EXP eingeführt, dass der jeweiligen Expectation automatisch einen eindeutigen Namen vergibt.

    mimicpp::Mock<void()> myMock{};
    SCOPED_EXP myMock.expect_call();
    myMock();	// consumes myExpectation
    

    Was fehlt noch?

    Im Prinzip nicht mehr viel und ich plane auch in der nächsten Zeit einen ersten Release. Vor allem muss die Doku noch ein wenig ausgebaut werden.
    Ich möchte allerdings auch noch polymorphe Mocks ein wenig besser supporten. Derzeit müsste explizit die zu überschreibende Methode definiert und alles an den
    entsprechenden Member Mock weitergeleitet werden; das ist doch noch ein wenig sehr umständlich. Wahrscheinlich läuft das auf ein weiteres (optionales!) Makro hinaus. Wenn hier jemand eine Idee hat, gerne her damit 🙂

    Hier ist das github Repo: https://github.com/DNKpp/mimicpp
    Die generierte Doxygen Doku kann man hier finden: https://dnkpp.github.io/mimicpp/
    Und ein paar Beispiele kann man hier finden.
    Zusätzlich habe ich einen kleine Spielplatz auf godbolt.org eröffnet, auf dem man selbst direkt herumprobieren kann: klick mich

    Ich würde mich über konstruktives Feedback wirklich sehr freuen 🙂

    Gruß Dominic


Anmelden zum Antworten