Thread: [Cppunit-devel] Some interesting ideas I am looking at
Brought to you by:
blep
From: King D. <Ki...@tc...> - 2001-11-30 15:45:53
|
First, I recently discovered the idea of MockObjects (www.mockobjects.com) which is sort of a framework for creating stub-like objects (mock objects are not the same as a stub) upon which you can set expectations and they will verify themself. For instance you could create a mock ostream object and tell it what you expect to be written to it and if something else is written then it will fail. Before discovering the idea, I already did something like this, but it was all hand written as opposed to using a ready-made framework. There are mockobjects for Java that work with Junit, but none for C++ so I started some work on creating a C++ equivalent. However, just as with cppunit things would be a whole lot nicer if C++ had reflection like Java does. While doing some research, I stumbled across something called OpenC++ (http://www.csg.is.titech.ac.jp/~chiba/openc++.html). It is kind of hard to explain what exactly OpenC++ is (the documentation does a very lousy job), but it is sort of translating preprocessor for C++ that lets you add your own language extensions. It reads in your source files and various meta classes that you write and spits out C++ code. You have full access to the parse tree of the source code and can modify it and do reflection. You could think of it as a much smarter version of the preprocessor, but that would hardly be doing it justice. I know my explanation does not do it justice, but consider an example related to CppUnit. Instead of all the mucking about with preprocessor macros and templates like CPPUNIT_TEST_SUITE stuff, you could actually define a language extension using for example class and method modifiers (testsuite and testcase in the example): class testsuite FooBarTests { public: testcase void testFoo(); testcase void testBar(); }; And this could generate the suite method adding all test cases to it, getting their names from their declarations. An alternative syntax idea could be to use a user defined access modifier class testsuite FooBarTests { public: testcases: void testFoo(); void testBar(); }; Or the testsuite metaclass could do like junit and simply add all methods with a signature of void testXXX() as test cases. There are many possibilities. This would also be helpful in something that is a big problem right now with CppUnit, how to use decorators with the macros. Currently you can't and there isn't a good solution particularly with the notion that decorated tests have a variable number of parameters. But imagine doing: class testsuite FooBarTests { public: testcase decorator( RepeatedTest, 5 ) void testFoo(); testcase void testBar(); }; This would decorate the testFoo case, by wrapping it with a RepeatedTest test decorator with a parameter of 5. (Of course test decorators need to get their test ownership issues fixed). It would be a lot cleaner, and avoid duplication of names as macro parameters. This would be helpful with MockObjects, because in the Java version you can create a mock object and it uses reflection to just examine the class of the object and iterate through all fields looking for ones that implement the Expectation interface and calls their verify method. All it took to add an expectation was to add the field to the class. Of course in straight C++ it is not so simple. I could try to do something like what CppUnit does with the CPPUNIT_TEST_SUITE stuff which requires declaring things twice. But I think a better idea is to use OpenC++ and extend the language to add mockobjects that would generate code that called verify on all members that implement the Expectation interface. I just thought I would solicit any thoughts on the subject from the group. Note, I am going on vacation tomorrow so it will be a week or so before I get back with anyone. |
From: Baptiste L. <bl...@cl...> - 2001-12-13 22:08:27
|
Some interesting ideas I am looking atHow about changing the original design a little bit: class Verifiable { virtual void verify() = 0; }; class Expectation : public Verifiable { ... }; // A new base class for all object that contains expectation // C++ allows mutliple inheritance, so we can use a base class // for all object that contains Expectation class VerifiableObject : public Verifiable { public: void addVerifiable( Verifiable * pVerifiable ) { m_verifiables.push_back( pVerifiable ); } void verify() { for ( int index = 0; index < m_veriables.size(); ++index ) m_verifiables[index]->verify(); } private: std::deque<Verifiable *> m_verifiables; } // Our expectation register themself to an object in the constructor class ExpectationCounter : public Expectation { public: ExpectationCounter( VerifiableObject *object, std::string message ) { object->addVerifiable( this ); ... } }; class MyMockObject : public VerifiableObject { public: MyMockObject() { m_computeCalls = new ExpectationCounter( this, "compute calls" ) } ... }; What do you think ? It looks a lot simpler for me, though not has beautiful as the java design, it should work. Baptiste. ----- Original Message ----- From: King Dale To: 'cpp...@li...' Sent: Friday, November 30, 2001 4:44 PM Subject: [Cppunit-devel] Some interesting ideas I am looking at First, I recently discovered the idea of MockObjects (www.mockobjects.com) which is sort of a framework for creating stub-like objects (mock objects are not the same as a stub) upon which you can set expectations and they will verify themself. For instance you could create a mock ostream object and tell it what you expect to be written to it and if something else is written then it will fail. Before discovering the idea, I already did something like this, but it was all hand written as opposed to using a ready-made framework. There are mockobjects for Java that work with Junit, but none for C++ so I started some work on creating a C++ equivalent. [...] --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/ |