Unit Testen einer Funktion, die im Fehlerfall nicht stoppt



  • Da war ich möglicherweise schon etwas weiter im Kopf ohne die entsprechenden Informationen nachzuliefern 🙂

    Die fehlende Information war vermutlich: Jetzt wo ich so eine Abstraktion für std::cout / std::cin habe, möchte ich die auch in anderen Funktionen das Konsolen Interfaces nutzen. Denn auch die profitieren dann ja von den Möglichkeiten zum Mocken.

    Zum Beispiel habe ich Methoden:

    • Um Daten einzugeben
    • Um Daten auszugeben

    Also sprich die Methoden, in denen ich eben unter anderem auch so eine "getInput" Methode verwende. Ist ja erstmal ganz sinnig auch da eben meine ConsoleIO Klasse zu nutzen, damit ich auch für diese Methoden mocken kann.
    Da kannst du dir aber vlt. vorstellen, dass ich mehr als nur eine Zeile Text ausgebe, sondern vlt. eher sowas habe:

    Console consoleIO; 
    consoleIO << "Das sind die Daten: " << someDataObject << "\n";
    

    Also eben entsprechend auch verketten will (deswegen der operator<<) und eben (das ist das Problem) auch nicht nur Strings ausgeben möchte. Sondern z.B. auch integer, floats und alle anderen selbstgeschrieben Objekte oder Objekte einer Lib, die eben den Operator<< für sich definieren.

    Und all das geht eben nicht mehr mit ConsoleIO. Weder andere primitive Datentypen noch eben komplexe Datentypen, die den operator<< mit einem std::iostream definieren (wie es ja quasi Standard ist).

    Jetzt hatte ich mich gefragt: Kann man das ändern? Ich würde eben nicht gerne alles erst in einen String konvertieren (Indem ich z.B. alles erstmal in einen stringstream schiebe).

    Das einfachste dazu, was mir einfällt sind Templates. Mein ConsoleIO Klasse ist ja nur einen wrapper von daher sollte das ja erstmal ohne Probleme funktionieren. Mein operator<< oder auch "writeLine" Methode nimmt jeden Datentypen entgegen und delegiert weiter and std::cout.

    Nur können Templates ja nicht virtual sein. Und das ist ja der Hauptgrund, warum ich diesen Wrapper überhaupt schreibe 😃

    Auf eine Lösungsidee habe ich mich grade selbst während dem Schreiben gebracht! 🙂 Ich könnte es natürlich so machen:

    class ConsoleIO {
    public:
        virtual ~ConsoleIO();
        virtual std::string readLine();
        virtual void writeLine(std::string_view line);
    
       template <typename T>
       ConsoleIO& operator<<(T& data) {
           std::ostringstream stream {}; 
           stream << data; 
           writeLine(data.str()); 
           return *this;
       }
    };
    

    Also, sofern ich das jetzt grade aus dem Kopf einigermaßen syntax mäßig korrekt gemacht habe: Ich schreibe eine Template Methode, die eben alles mit ostringstream in einen string konvertiert. Dann rufe ich damit meine writeLine Metode auf und auch nur die mocke ich letzendes.

    Damit sollte ich eigentlich meine ConsoleIO Klasse mit allen möglichen Datentypen aufrufen können, auch denen die irgendwo einen eigenen operator<< definiert haben. Und trotzdem kann ich das ganze Mocken.
    Beim Mocken muss man halt hier nur aufpassen, da console << "Teil 1" << "Teil2" << "Teil3" natürlich in 3 Aufrufen resultiert und nicht nur in einem 🙂



  • @Leon0402 sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Beim Mocken muss man halt hier nur aufpassen, da console << "Teil 1" << "Teil2" << "Teil3" natürlich in 3 Aufrufen resultiert und nicht nur in einem

    Ja. Weswegen ich das auch eher vermeiden würde. Also besser writeLine (oder writeMessage oder was auch immer) wird immer nur mit einer fertigen Nachricht aufgerufen, nicht mit Stücken.

    Ansonsten gibt's natürlich noch die Möglichkeit im Mock bei writeLine das Zeug einfach nur in einen Stream zu stopfen (z.B. in eine std::stringstream Membervariable) und die Checks dann alle in readLine zu machen.

    Wobei dein Stream-Insertion Operator ein weiteres Problem hat:

       template <typename T>
       ConsoleIO& operator<<(T& data) {
           std::ostringstream stream {}; 
           stream << data; 
           writeLine(data.str()); 
           return *this;
       }
    

    Du kannst da wunderbar sämtliche "modifier" (std::hex etc.) reinstecken, wird fehlerfrei kompilieren. Nur Auswirkung wird es keine haben.

    Also mMn.: entscheide dich für eine Variante. Entweder gleich direkt mit Streams (und dann halt ohne Unit-Tests oder mit komplizierten Stream-Buffer Mocks für die Unit-Tests). Oder mit einem eigenen Interface - aber dann ohne iostream-artigen Stream-Insertion Operator.

    Beides in Kombination halte ich für Quatsch.

    Falls du dich für eigenes Interface ohne iostream-artigen Stream-Insertion Operator entscheidest: guck dir https://github.com/fmtlib/fmt an. Damit kann man sehr schön (und sehr performant) Text "formatieren".



  • @hustbaer sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Du kannst da wunderbar sämtliche "modifier" (std::hex etc.) reinstecken, wird fehlerfrei kompilieren. Nur Auswirkung wird es keine haben.

    Wobei mir die Funktionalität mit dem writeLine ja auch verloren geht, letzenendes. Berechtigt ist aber natürlich auf jeden Fall die Kritik, dass es fehlerfrei kompiliert. Wobei das vermutlich behebar wäre?

    Konkret würden mir da jetzt zwei Lösungsmöglichkeiten einfallen:

    Zum einen eine Template Spezialisierung für Manipulatoren (Wüsste zwar auf Anhieb nicht wie, aber da ich das in dem ostream Code als Überladung gesehen habe, sollte das ja gehen) und darin dann asserten. Okay Manipulatoren gehen immer noch nicht, aber zumindest sollte ne Fehlermeldung geschmissen werden 🙂

    Eine weitere Möglichkeit wäre den ostringstream als Member zu haben und nur in diesen im operator<< zu schreiben:

    template <typename T>
    ConsoleIO& operator<<(T& data) {
           stream << data; 
           return *this;
    }
    

    Dann eine Art eigenen Manipulator zu schreiben. Der Einfachheithalber jetzt vlt. einfach mal ein

    struct flush {};
    inline Flush flush;
    

    und eine entsprechende Template Spezialisierung für den operator

    template <>
    ConsoleIO& operator<<(flush& data) {
           writeLine(stream.str()); 
           stream = ostringstream {};
           return *this;
    }
    

    Die Benutzung erfolgt dann:

    console << "This " << "is " << "my " << "data " << flush; 
    

    Wenn ich mich nicht komplett irre sollten dann auch die modifier alle gehen (Zumindest sowas wie std::hex ... bin mir nicht so 100% sicher, was genau es alles für modifier gibt und ob alle mit nem ostringstream gehen).

    Gleichzeitig ist hiermit auch das Problem der mehreren calls gelöst. Eine Zeile -> Ein Call beim Mocken.

    Der einzige Nachteil den ich hier sehe ist, dass man halt manuell irgendwie flushen muss (Und das man es potentiell vergessen könnte). Könnte man jetzt auch über ne extra Methode machen anstatt da direkt so im Stream.
    Aber aus meiner Sicht könnte man denke ich mit den Nachteilen hier leben.

    Hab ich was übersehen? Gibt es andere Probleme mit dem Lösungsvorschlag?

    @hustbaer sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Also mMn.: entscheide dich für eine Variante.

    Ich möchte nicht deine Meinung in Frage stellen. Ich finde es nur interessant und recht lehrreich meinen Ansatz noch etwas weiterzuverfolgen. Schon einiges in diesem Thread gelernt, vielen Dank 🙂

    Vermutlich ist die Entscheidung, wenn das hier nichts wird mit meinem Ansatz oben, dann eher erstmal ostringstream weiter zu nutzen für Mocks oder gar nicht die Methoden unit zu testen. Aber ich werde mir auf jedenfall die fmt lib mal anschauen. Ist ja jetzt mit std::format auch im C++ Standard 🙂



  • @Leon0402 sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Eine weitere Möglichkeit wäre den ostringstream als Member zu haben und nur in diesen im operator<< zu schreiben:

    Kann man machen. Man könnte das aber genau so gut über eine unabhängige Hilfsklasse machen. Dann hätte man die Aufgaben "Console IO" und "Text-Formatierung" schöner getrennt.

    Dem "Console IO" Teil kann es schliessliche egal sein wie der Text formatiert wird, und dem Text-Formatierungs Teil kann es egal sein wo die Daten hingehen.



  • Was spricht denn generell gegen eine virtuelle (protected) Methode, die einfach nur eine referenz auf ein std::ostream zurückliefert?
    std::ostream& stream();
    Das ist doch das, was dein ConsoleIO eigentlich wegabstrahiert: Welches konkrete ostream Objekt du nun eigentlich wirklich verwendest.
    Jedenfalls ließe sich auf diese Weise ein templatetisierter op << bauen, in dem man diesen einfach nur für die Basisklasse baut.

    template <class TEgal>
    MyBaseClass& operator << (const TEgal& data)
    {
        stream() << data;
        return *this;
    }
    


  • @DNKpp
    Und wie bekommt die Klasse dann mit dass in diesen ostream eine fertige Nachricht geschrieben wurde?



  • @hustbaer sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    @DNKpp
    Und wie bekommt die Klasse dann mit dass in diesen ostream eine fertige Nachricht geschrieben wurde?

    Muss sie das denn? Ich habe mir ehrlich gesagt nicht jeden eurer Posts durchgelesen, aber so wie es aus seinem letzten Post scheint, will er ja ein flush "signal" via Manipulator senden. Also würde doch ein std::endl oder std::flush reichen? Man muss hier ja keinen ostringstream rausreichen. Es reicht ja auch der tatsächliche target stream und der lässt sich ja wie gehabt durch die beiden genannte Manipulatoren flushen.



  • Wenn ich das richtig verstehe ist deine Variante so ein Zwischending zwischen meinen beiden vorgestellten Varianten.

    class ConsoleIO {
        std::ostream stream = std::cout; // Das könnte man per Konstruktor übergeben
    
        virtual std::ostream& stream() {
              return stream;
        }
    
       template <class TEgal>
       MyBaseClass& operator << (const TEgal& data)
       {
          stream() << data;
          return *this;
      }
    };
    

    Also so ausgeschrieben.

    Vorteile:

    • Benutzung wie mit std::cout direkt, auch kein flush Manipulator nötig
    • Auch Manipulatoren werden unterstützt

    Das Hauptproblem hier ist, dass die Methode nicht wirklich mockbar ist.

    • Man muss in der (vom Framework) überschriebenen stream() Methode immer einen stream zurückgeben. Man weiß auch nicht, was genau in den Stream geschrieben wird (zum Zeitpunkt des Methodenaufrufes), womit die Vorteile des Mocks eher geringfügig sind.
      Z.B. Kann man nicht mehr sagen: Die stream Methode muss mit dem Argument "Hello Wolrd" 3x aufgerufen werden.
    • Eine kleinere Unschönheit, mit der ich aber leben könnte, ist auch das in dieser Variante eben wieder jede << Operation zu einem Mock Aufruf führt.

    Im Grunde hast du, wenn ich dich richtig verstanden habe, einfach eine "dummy Methode" dazwischen geschaltet. Die aber leider halt auch entsprechend nicht so viel kann.



  • @hustbaer sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    @Leon0402 sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Eine weitere Möglichkeit wäre den ostringstream als Member zu haben und nur in diesen im operator<< zu schreiben:

    Kann man machen. Man könnte das aber genau so gut über eine unabhängige Hilfsklasse machen. Dann hätte man die Aufgaben "Console IO" und "Text-Formatierung" schöner getrennt.

    Dem "Console IO" Teil kann es schliessliche egal sein wie der Text formatiert wird, und dem Text-Formatierungs Teil kann es egal sein wo die Daten hingehen.

    Das heißt es gibt "quasi" nichts zu meckern an meinem Ansatz? Das man die Formattierung raustrennen könnte ist natürlich ein valider Einwand. Das ganze war jetzt eben an std::cout orientiert, wo ja auch beides miteinander vermischt wird.

    Ich denke aber das wohl einfachste / schönste (und ich glaube das hast du auch weiter oben gemeint als du fmt erwähnt hast) wäre wohl:

    class ConsoleIO {
    public:
        virtual ~ConsoleIO();
        virtual std::string readLine();
        virtual void writeLine(std::string_view line) {
           outputStream >> line;
        }
    
        ConsoleIO& operator<<(std::string_view line) {
           writeLine(line);
           return *this;
        }
    
    private: 
        // Per Konstruktor im besten Fall setzen
        ostream outputStream = std::cout;
        istream inputStream = std::cin;
    };
    

    Und dann statt mit ConsoleIO zu formatten, eben einfach immer mit std::format (bzw. fmt):

    console << std::format("Hello {}", world);
    

    format kann soweit ich das verstanden habe, nämlich auch Objekte mit überladenem operator<< nutzen. https://fmt.dev/latest/api.html#std-ostream-support

    Das ist mit Abstand die einfachste und vermutlich beste Option würde ich sagen. Der einzige Nachteil, der mir einfällt ist das man halt eine extra lib braucht (solange std::format nicht implementiert ist) bzw. sich halt etwas umgewöhnen muss. Aber an sich finde ich std::format eig. auch die beste Option und sauber ist das Formatting & Ausgabe auch getrennt.

    Ich wünschte nur es gäbe format strings. Also einfach statt std::format("...", ...); lieber f"...". Das wäre ein Traum 🙂



  • Ja, so ungefähr. Side-Note: Du solltest std::cout natürlich nicht kopieren.

    Um dir wirklich zu helfen, müsste ich allerdings mal sehen, was du eigentlich genau vor hast. Viele Wege führen sicherlich zum Erfolg. Einen (hoffentlich) sinnvollen kann ich dir allerdings erst zeigen, wenn ich das Problem richtig erfasst habe. Du hast ja innerhalb dieses Threads schon die ein oder andere Problem-Transformation vorgenommen, daher kann ich dir leider auch nicht mehr ganz folgen.

    An sich macht das, was @hustbaer sagt, dass dein ConsoleIO nicht zwingend zum Formatieren verdonnert werden soll, ja schon mal sehr viel Sinn. Generell frage ich tatsächlich, wofür du diese ConsoleIO Klasse nun wirklich reell benötigst, bzw warum das generell eigentlich eine Hierarchie sein muss. Reicht dir denn eine einfache Komposition nicht (also austauschbares Verhalten der Member, statt der ganzen Klasse).

    @Leon0402 sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Ich wünschte nur es gäbe format strings. Also einfach statt std::format("...", ...); lieber f"...". Das wäre ein Traum 🙂

    Die stl bietet ja durchaus schon eigene literale an, um strings zu bauen. Ich denke es sollte durchaus möglich sein, sowas selbst zu definieren (".."s für std::string, "..."sw für std::string_view wenn ich mich nicht irre)
    https://en.cppreference.com/w/cpp/string/basic_string/operator""s

    Dazu mal das hier: https://en.cppreference.com/w/cpp/language/user_literal



  • Das große Ziel ist es mocken zu können mit https://github.com/rollbear/trompeloeil. Die Grundidee ist dabei die folgende:

    • Du hast eine Funktion mit einer Abhängigkeit, die du testest auf die (unter anderem eins der folgenden Dinge zutrifft):
      • Abhängigkeit sehr komplex / langsam / nicht-deterministisch (z.B. System Zeit, Datenbank)
      • Abhängigkeit liefert Input in deine Funktion den du nicht (oder sehr schwer) kontrollieren kannst -> keine Kontrolle welche Pfade in deiner Funktion ausgeführt werden (z.B. In meinem Beispiel habe ich keine wirkliche Kontrolle über den Input der aus std::cin kommt, aber wichtig dafür ist, welchen Pfad meine Funkton einschlägt)
      • Deine Funktion hat kein sichtbares testbares Verhalten z.B. Rückgabewert, Änderung des Zustands etc., sondern einen Art Seiteneffekt (z.B. bei mir die Ausgabe auf std::cout ... die ist erstmal so nicht direkt abfragbar)
    • Deine Funktion erlaubt es deine Abhängigkeit irgendwie auzutauschen, z.B. indem es diese eben per Parameter entgegenimmt
    • Du schreibst mit Hilfe der Makros der Lib eine Subclasse deiner Abhängigkeit. Im Grunde definierst du nur, welche Methoden du alles hast (normalerweise geht das mit Reflection automatisch)
    • Die Lib füllt die Klasse mit konkreten Implementationen, die mehr oder weniger sich nur speichern wie oft / wann / mit was welche Methode aufgerufen wird und irgendwelche dummy Werte zurückgibt
    • In deinem Test packst du eben ein Objekt dieser erstellen Mock Klasse in deine Funktion unter Test rein
    • Dann hast du die Möglichkeit "Expectations" zu setzen. Du sagst: "Methode A darf beliebig oft aufgerufen werden", "Methode B darf nur mit Parameter xyz aufgerufen werden", "Methode3 muss genau 3x aufgerufen werden", "Methode D gibt immer einen nullptr zurück", "Methode E darf erst aufgerufen werden, nachdem Methode D aufgerufen wird", "Methode F gibt bei Parameter abc eine 0 zurück, ansonsten eine 1". Du kannst also ziemlich genau spezifzieren, was genau mit welcher Methode gemacht werden darf.

    In meinem Beispiel (und auch in anderen nicht gezeigten( hatte ich ja konkret zwei Probleme:

    • Den Input von std::cin / std::getline bestimmt welcher Pfad der Funktion ausgeführt wird. Es ist daher wichtig, dass ich genau kontrollieren kann, was std::getline denn einliest, um a) Jeden Testfall abzudecken b) Damit der Test schnell läuft c) Deterministisch ist
    • Es gibt einige Seiteneffekte / nicht direkt testbare Ergenisse -> Im Fehlerfall soll über std::cout eine Fehlermeldung angezeigt werden, es soll überprüft werden, dass der User erneut eine Eingabe tätigen kann bei einer falschen vorher etc.

    Diese Probleme habe ich gelöst bekommen, indem ich mein std::cout / std::cin durch stringstreams ersetzt habe. Denn diese bieten einige, aber bei weitem nicht alle Möglichkeiten eines Mocks u.a. den Input kontrollieren und den output "aufzeichnen", sodass dieser abgefragt werden kann.

    Es ist halt nur nicht super robust gewesen. Zum Beispiel um den Fehlerfall meiner Methode zu testen, musste man einmal einen invaliden Input reingeben und dann eben nochmal einen validen Input beim zweiten Durchgang, um der Endlossschleife zu entkommen. Das habe ich dann z.B. so gelöst:

    std::istream inputStream {"invalid\nvalid"};
    

    Sprich mit einem "\n" in der Mitte, damit eben bei einem >> erst der eine und beim zweiten mal der andere Teil eingelesen wird.
    Und so "Tricks" habe ich dann halt verwendet, um das ganze zu testen. Ist okay, es funktioniert, aber gefallen hat es mir nicht. Wer so einen Test sieht, fragt sich auch erstmal, was ich da gemacht habe 😃

    @hustbaer Meine dann: Warum nicht mocken? -> Mehr Möglichkeiten, besser sichtbar was man da eig. macht, robuster etc.

    Und daraufhin ist quasi hier etwas die Diskussion entbrannt wie man denn überhaupt std::cout und std::cin mockt. Insbesondere dann, wenn man halt nicht nur Strings ein -und ausliest. Seitdem sind verschiedene Ideen entstanden wie man das mehr oder weniger schön mocken kann.

    Die zwei besten Kanidaten aktuell sind imo:

    • In einen stringstream schreiben und eben manuell flushen. Die Methode flush / der Manipulator oder whatever sollte aber nicht direkt flushen, sondern nochmal an writeLine deligieren. Die Idee dahinter ist, dass man eben eine Methode mockt, die den entsprechenden String auch als Parameter bekommt, sonst gehen dir viele Möglichkeiten des Mockens eben wieder verloren (-> Mein Kandidat der Wahl, wenn ich gerne das stream inserten behalten möchte)
    • Tatsächlich nur noch strings ein und auslesen und z.B. beim formattieren Hilfe von fmt / std::format zu nehmen etc. (-> Aus meiner Sicht aktuell die beste Möglichkeit, insbesondere dann wenn std::format benutzt werden kann. Man muss halt seinen Code dafür umschreiben bzw. ggf. ne Lib einbinden)


  • @DNKpp sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Die stl bietet ja durchaus schon eigene literale an, um strings zu bauen. Ich denke es sollte durchaus möglich sein, sowas selbst zu definieren (".."s für std::string, "..."sw für std::string_view wenn ich mich nicht irre)
    https://en.cppreference.com/w/cpp/string/basic_string/operator""s
    Dazu mal das hier: https://en.cppreference.com/w/cpp/language/user_literal

    Daran dachte ich auch schon. Ich möchte mir halt nur sowas nicht selbst bauen 😃 Sowas sollte dann wenn dann im C++ Standard sein. Aus meiner Sicht eben auch direkt als Sprachkonstruktur ähnlich wie bei z.B. raw Strings etc.
    Aber fürs erste würde ich mich schon freuen, wenn die Compiler endlich mal std::format implementieren 😉



  • @Leon0402 sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Also einfach statt std::format("...", ...); lieber f"...". Das wäre ein Traum

    Wie gibst du dann die Argumente da rein?
    Boost.Format macht das so ähnlich, nur muss man dann wieder extra was machen um an den finalen String zu kommen: str(boost::format("...") % a % b). Könnte man jetzt mit user-defined literals schreiben ala str("..."_fs % a % b). Aber ist das wirklich signifikant besser als std::format("...", a, b)?



  • @hustbaer sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    @Leon0402 sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Also einfach statt std::format("...", ...); lieber f"...". Das wäre ein Traum

    Wie gibst du dann die Argumente da rein?
    Boost.Format macht das so ähnlich, nur muss man dann wieder extra was machen um an den finalen String zu kommen: str(boost::format("...") % a % b). Könnte man jetzt mit user-defined literals schreiben ala str("..."_fs % a % b). Aber ist das wirklich signifikant besser als std::format("...", a, b)?

    f"Variable {a}, Variable {b}, Variable {c}" 
    

    und möchte man die Variablen auch irgendwie formattieren

    f"Variable {a:%Y-%m-%d %H:%M}, Variable {b:3}, Variable {c}" 
    

    Also sprich ein Doppelpunkt und dahinter was auch immer es für formatting optionen gibt z.B. Für Datums Objekte, Anzahl an Stellen etc.

    Die Variante mit % kenne ich auch, finde ich aber nur geringfügig besser, wenn überhaupt. Format Strings fänd ich tatsächlich dagegen deutlich schöner nochmal, insbesondere wenn man viele Argumente hat. Dann ist es einfach übersichtlicher.



  • Die Art von String-Iterpolation wo man den Variablen-Namen einfach ala "Hello {username}!" in den Format-String mit reinschreibt geht in C++ nicht.



  • @hustbaer sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Die Art von String-Iterpolation wo man den Variablen-Namen einfach ala "Hello {username}!" in den Format-String mit reinschreibt geht in C++ nicht.

    Ich verstehe nicht ganz, was du meinst? Es ist mir klar, dass das aktuell nicht geht ... es war ja auch nur ein Wunsch von mir, dass sowas in die Sprache eingebaut wird.

    @Leon0402 sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    ch wünschte nur es gäbe format strings. Also einfach statt std::format("...", ...); lieber f"...". Das wäre ein Traum

    @Leon0402 sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Aus meiner Sicht eben auch direkt als Sprachkonstruktur ähnlich wie bei z.B. raw Strings etc.

    Oder gibt es eine andere technische Begründung, warum sowas auch nicht in Zukunft in C++ gehen könnte



  • @Leon0402 sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    @hustbaer sagte in Unit Testen einer Funktion, die im Fehlerfall nicht stoppt:

    Die Art von String-Iterpolation wo man den Variablen-Namen einfach ala "Hello {username}!" in den Format-String mit reinschreibt geht in C++ nicht.

    Ich verstehe nicht ganz, was du meinst? Es ist mir klar, dass das aktuell nicht geht ... es war ja auch nur ein Wunsch von mir, dass sowas in die Sprache eingebaut wird.

    Ich meine es geht nicht im Sinn von man kann es sich auch nicht selbst schreiben, weil es die Core-Language nicht hergibt.
    Die Diskussion mit @DNKpp klang für mich so als ob zumindest einer von euch annimmt dass das ginge.


Anmelden zum Antworten