frage zu templates ??



  • hi an alle,

    ich arbeite gerade mit cppunit und visual c++, es geht aber mehr
    um templates... und zwar möchte ich meine testfälle aus einer textdatei holen, die ungefähr so aussieht:

    TestCaseClass.myNumberTest
    TestCaseClass.myOtherTest

    Der jetzige code sieht so aus, die testfälle werden noch nicht aus der datei gelesen.

    runner.addTest( new CppUnit::TestCaller<TestCaseClass>("myNumberTest",  &TestCaseClass::myNumberTest) ); 
    runner.addTest( new CppUnit::TestCaller<TestCaseClass>("myOtherTest", &TestCaseClass::myOtherTest) );
    

    ich möchte das jetzt dynamisch in einer schleife aus der datei lesen und die entsprechenden addTest methoden aufrufen. wie würdet ihr das programmieren?

    Das problem ist, dass aus der textdatei nur strings kommen und ich nicht weiss,was ich mit dem template machen soll, weil es ja eine Klasse als paramter bekommt. in java würde man da wohl mit reflection rangehen, aber was ist in c++? hoffe ihr habt mein problem verstanden 🙂



  • Da wirst du wohl nicht um ein Programm/Skript rumkommen, womit du die Datei ausliest und den entsprechenden Code generierst.

    C++ wird eben (üblicherweise) kompiliert. Da kann man Templates etc. nicht dynamisch generieren.



  • TestCaseClass.myNumberTest 
    TestCaseClass.myOtherTest
    

    Was soll das bedeuten?

    ... CppUnit::TestCaller<TestCaseClass> ...
    ... CppUnit::TestCaller<TestCaseClass> ...
    

    Sehe an der Stelle eher das Problem darin, dass man irgendwo definieren muß was der Test macht. (Wenn ich das richtig interpretiere, ist das aktuell durch eine statische Funktion gelöst. Das Template ist an der Stelle weniger das Problem)



  • der code ist nicht so wichtig, es geht eher um templates...Es soll leider nicht compiliert werden !!

    in einer datei steht in jeder Zeile immer die Klasse und der entprechende Testfall, z.b.

    Auto.testFahre
    Fahrrad.testReifen
    Bus.testBenzin

    nunbietet CppUnit die Methode addTest an, um die entsprechenden Tesfälle in eine Testsuite zu fügen.

    suiteOfTests->addTest(new CppUnit::TestCaller<Auto>("testFahre",&Auto::testFahre));
    
    suiteOfTests->addTest(new CppUnit::TestCaller<Fahrrad>("testReifen",&Fahrrad::testReifen));
    
    suiteOfTests->addTest(new CppUnit::TestCaller<Bus>("testBenzin",&Bus::testBenzin));
    

    Da ich vorgesehen habe, die Testfälle aus einer Datei zu holen und in einer schleife dynamisch einzulesen, bräuchte man so etwas: (in java reflection genannt)

    suiteOfTests->addTest(new CppUnit::TestCaller<getClassByName("Auto")>("testFahre",&getClassByName("Auto::testFahre"));
    

    ansonsten müsste ich mit 1000 if, switch und case Anweisungen arbeiten, um die strings zu vergleichen.

    if (string == Auto.testFahre) {
    suiteOfTests->addTest(new CppUnit::TestCaller<Auto>("testFahre",&Auto::testFahre));
    }
    

    und das wollte ich vermeiden ...



  • lol.
    muahahaha.
    😃 😃 😃

    Das geht in C++ nicht (leider)

    Aber du gehst dein Problem ärschlings an. Sag mal einfach: was willst du denn damit erreichen, nicht wie du gedenkst es zu erreichen.



  • mentalman schrieb:

    ...
    ansonsten müsste ich mit 1000 if, switch und case Anweisungen arbeiten, um die strings zu vergleichen. ...

    Naja, Du kannst natürlich auch mit einer

    typedef std::map<std::string, void (*)(void) > FuncMap;
    

    arbeiten.
    Damit bist Du zwar zur Compilezeit auch "festgelegt", aber immerhin ist die Pflege recht easy und selbsterkärend.

    FuncMap funcMap;
    
    // füllen
    funcMap["myNumberTest"] = &myNumberTest;
    funcMap["myOtherTest"] = &myOtherTest;
    ...
    
    // call
    FuncMap::const_iterator it = fm.find(fname);
    if(it != fm.end()) (*(it->second))();
    

    Da "passen" zwar auch statische Memberfunktionen rein, aber ich persönlich würde auf die "TestCaseClass" sowieso komplett verzichten ... braucht's nicht und ist wohl auch keine objektorientierte Aufgabenstellung.
    (Alternativ geht auch eine

    typedef std::map<std::string, void (TestCaseClass::*)(void)> funcMap;
    FuncMap funcMap;
    
    // füllen
    funcMap["myNumberTest"] = &TestCaseClass::myNumberTest;
    funcMap["myOtherTest"] = &TestCaseClass::myOtherTest;
    ...
    
    // call
    TestCaseClass a;
    FuncMap::const_iterator it = fm.find(fname);
    if(it != fm.end()) (a.*(it->second))();
    

    )

    Wenn Du Klassendeklarationen dynamisch zur Laufzeit laden willst, gibt's da im C++-Standard (AFAIK) keine Festlegung. Vielleicht hat boost da was ... ansonsten mußt Du Dir das selbst programmieren (wird aber hakelig, denke ich).
    Ehrlich gesagt halte ich derartige Flexibilisierung über für oftmals unnötig....

    Gruß,

    Simon2.



  • Naja man braucht an der Stelle eine Verwaltung für die existierenden Testklassen bei der zur Laufzeit alle angemeldeten Klassen per Id abfragbar sind.

    Dies kann man wie beschrieben über Funktionspointer lösen... geht aber auch in dem man ein Objekt der jeweiligen Klasse anmeldet und dann eine Funktion Clone () aufruft.
    🙂



  • danke für die antworten..

    @simon2: kannst du die konstruktion

    typedef std::map<std::string, void (*)(void) > FuncMap;
    

    noch mal erkären? ist das ein hashtable?? c++ ist ganz schön kryptisch manchmal..damit kann ich mich nicht so richtig anfreunden 😉



  • mentalman schrieb:

    typedef std::map<std::string, void (*)(void) > FuncMap;
    

    noch mal erkären? ist das ein hashtable?? c++ ist ganz schön kryptisch manchmal..damit kann ich mich nicht so richtig anfreunden 😉

    Das ist ein typedef auf eine map, um Schreibarbeit zu sparen. Der Schlüssel (der ist eindeutig) ist ein std::string. Jedem Schlüssel ist ein Funktionszeiger auf eine Funktion, die nichts entgegennimmt und nichts zurückgibt zugeordnet.



  • ok .. erinnert mich an ein hashtable in java. jetzt habe ich folgendes und das kopiliert auch.. das problem ist nur da wo die fragezeichen stehen. welchen rückgabewert müsste die methode "getFunc" haben????

    Teil von .h :

    class TDDLI_TestCase:public CppUnit::TestCase  
    {
    	typedef std::map<std::string, void (TDDLI_TestCase::*)(void)> FuncMap; 
    
    public:
    	TDDLI_TestCase();
    	virtual ~TDDLI_TestCase();
    	???????? getFunc(string name);
    	void setUp();
    	void tearDown();
    	void test1();
    	void test2();
    	void test3();
    private:
    	 FuncMap funcMap; 
    };
    
    Teil von .cpp :
    
    TDDLI_TestCase::TDDLI_TestCase()
    {
    	funcMap["TDDLI_TestCase.test1"] = &TDDLI_TestCase::test1; 
    	funcMap["TDDLI_TestCase.test2"] = &TDDLI_TestCase::test2; 
    	funcMap["TDDLI_TestCase.test3"] = &TDDLI_TestCase::test2; 
    }
    
    ??????????? getFunc(string name)
    {
    	return funcMap[name];
    }
    


  • Den Funktionszeiger (bzw. eigentlich Methodenzeiger). Dafür machste aber am Besten auch noch 'n typedef. Hier ein schönes Tutorial: http://www.newty.de/fpt/index.html


Anmelden zum Antworten