"Unit-Test" mit User-Einwirkung
-
Hallo,
ich habe eine grundsätzliche Frage: Wie testet man optimal Funktionen, die abhängig von den Eingangsdaten noch verschiedene weitere Eingangsdaten brauchen? Das Problem ist nicht spezifisch für C++, sondern allgemeiner Natur.
Ein Beispiel:
std::string ersetzeTeil(std::string input, std::string neu) { // Diese funktion soll "neu" zurückgeben, wenn in input kein : vorhanden ist. // Anderenfalls soll sie "neu:<userabfrage>" zurückgeben. if(input.find(':') != input.npos) return neu; else return neu + ':' + userInput("Bitte etwas eingeben"); }
Natürlich ist der Code in der Funktion etwas komplizierter als hier gezeigt, aber es geht ums Prinzip.
Was möchte ich testen:
- ob "neu" zurückgegeben wird (kein Problem)
- ob der User gefragt wird, wenn ein : enthalten ist
- ob der richtige Wert zurückgegeben wird, wenn ein : enthalten ist3 Möglichkeiten, die mir einfallen, sind:
1)std::string ersetzeTeil(std::string input, std::string neu, std::string eingabeWennDoppelpunkt) { // nicht den user fragen bei :, sondern den übergebenen Wert verwenden }
Nachteil: Der User würde immer gefragt werden, auch wenn kein : enthalten ist. Möglicherweise hängt die Frage, die man dem User stellt, sogar noch von den Eingangsdaten ab, dann kann man diesen Ansatz komplett vergessen.
struct Ersetzer { Ersetzer(std::string input, std::string neu) : _input(input), _neu(neu) {} virtual std::string userInput() { // hier richtig den User fragen } std::string run(){ // normaler Algorithmus } private: std::string _input, _neu; };
In dem Test könnte man von der Klasse ableiten und userInput überschreiben, so wie man es haben möchte.
NAchteil: ziemlich großer Overheadtemplate <class Input> std::string ersetzeTeil(std::string input, std::string neu, Input inputFunc) { // anstatt userInput() den übergebenen Funktor aufrufen }
Hier müsste man bei jedem Aufruf der Funktion einen Funktor übergeben, der den User etwas fragt. Finde ich auch nicht so toll.
Wie macht man sowas elegant? Habt ihr noch andere Vorschläge? Wie gesagt, nicht C++-spezifisch, sondern allgemein. Es können auch Python-spezifische Sachen verwendet werden, da sich das Problem aktuell dort stellt
Liebe Grüße, Max
-
Ich würde zu 3) mit Produktions-Default tendieren.
std::string userInputProd(std::string const& prompt) { return userInput(prompt); } std::string userInputTest(std::string const& prompt) { return "xyz"; } template <class Input> std::string ersetzeTeil(std::string input, std::string neu, Input inputFunc = &userInputProd) { // anstatt userInput() den übergebenen Funktor aufrufen }