2016-07-30 17 views
3

Ich schreibe einen Komponententest, um einige API-Aufrufe zu überprüfen. Ich verwende einen Scheck, um zu testen. Mein Modul ist mit CMake gebaut (idk wenn es darauf ankommt).Function Mocking in C?

Mein Test ruft eine Funktion auf (die ich testen muss) und diese Funktion ruft einen anderen Binärcode auf.

Die vereinfachte Version sieht so aus.

/* unitTest.c */ 

#include "libraryAPI.h" 
void letsMakeACall(void) 
{ 
    ck_assert_eq(foo("water"), 0); 
} 

-- Module I am working on--- 
/*libraryAPI.c*/ 
#include "legacyLib.h" 

void foo(const char *drink)  
{ 

    if (checkDrink(drink)!=0) 
    { 
     return 1; 
    }else 
    { 
     return 0; 
    } 
} 


----LEGACY BINARY--- 
/*legacyLib.c*/ 

static const char* expected = "water"; 

void checkDrink(const char *drink) 
{ 
    if(drink == expected) 
    { 
     /*There are also a dozen functions being called which depend on legacy module initialisation*/ 
     return 0; 
    }else{ 
     return 1; 
    } 
} 

Ich möchte Antwort von LegacyLib verspotten, weil sonst Dutzende von Funktionen und Pausen aufrufen. Meine anfängliche Idee war, einige ifdef-Bedingungen hinzuzufügen, wenn Tests ausgeführt werden, aber es ist gegen Richtlinien. Weil es im Grunde eine Anrufüberwachung ist, weiß ich nicht, was es eine beste (oder funktionierende) Lösung ist. Was kann ich verwenden, um es zu lösen?

+0

Wenn Sie eine Funktion testen möchten, ist es nicht sinnvoll, „mock“ es. –

+0

Ja, aber ich möchte eine Antwort von einer der Funktionen, die von der Funktion, die ich testen möchte, aufgerufen werden. – Oreols

+2

Wo ist diese Funktion definiert? Können Sie die Bibliothek, die diese Funktion implementiert, durch eine "Schein" -Bibliothek ersetzen? –

Antwort

2

Ich bin auch nicht sicher, wie dies in der Regel zu lösen, habe ich eine similar question geschrieben, aber in einigen Fällen können Sie die folgenden (vorausgesetzt, Sie testen einzelne Funktionen):

  1. Fügen Sie die .c Datei statt des Headers .h, aber nachdem Sie „umbenennen“ Ihre verspottete Funktion einer Definition Direktive:

    #define checkDrink checkDrink_mocked 
    // preprocessor will now replace all occurrences of "checkDrink" 
    // with "checkDrink_mocked" 
    
    int checkDrink_mocked(const char *drink); 
    #include "legacyLib.c" 
    #undef checkDrink 
    
  2. die umbenannte Funktion implementieren:

    int checkDrink_mocked(const char *drink) 
    { 
        return 15; 
    } 
    
+0

Danke. Ich denke, das ist die beste Lösung. In meinem Fall war es eine sehr einfache Getter-Setter-Referenz, also habe ich einfach mein Modul neu implementiert (weniger Abhängigkeiten von dummen Dingen :)). – Oreols

+0

Großartig, froh, wenn es geklappt hat. Dies kann leicht fehlschlagen, wenn zum Beispiel eine 'libraryAPI.c'-Funktion eine externe Funktion von einem anderen Modul aufruft, die dann eine ursprüngliche Funktion von' libraryAPI.c' ('checkDrink' in diesem Fall) aufruft, weil der Linker dies tut finde die ursprüngliche Funktion dann. Ich habe eine Bibliothek namens mimick ([Snaipe/Mimick] (https://github.com/Snaipe/Mimick)) gefunden (der Autor erwähnt, dass sie immer noch in der Alpha-Phase ist), was durch Ändern der Einträge in der * "globalen Offset-Tabelle von das dynamische Modul zur Laufzeit "*, aber ich habe es nicht ausprobiert (es unterstützt anscheinend GCC 4.6+, Clang 3.5+, MSVC 14+). – Lou