How are these tests invoked? A separate test app? When the server
starts up? Have you looked at any of the prior art on unit test
frameworks?
>/**
> * Tester class is a composite member of Testable class
> * and acts as interface to Testable class for TestTool.
> */
This comment only makes sense once you understand how everything fits together.
>class Tester : public Loggable {
> friend Testable;
> public:
> /**
> * Constructor
> * @param name The name of the testable instance.
> * @param testable The mother testable.
> * @param logger The logger instance for log message dispatching.
> */
> Tester(const string &name,Testable *testable,Logger *logger);
Why do Tester and Testable both have names? It seems like
Tester::name() should call m_testable->name().
> /**
> * Method for generic test cases for TestTool.
> * @return True if tests were succesfull.
> */
> bool test();
>
> /**
> * Protected method for stress test cases for TestTool.
> * @return True if tests were succesfull.
> */
> bool stressTest();
How is stressTest supposed to work? You *really* need to put more
thought into writing the comments. Documenting classes isn't easy,
but it's important especially for a distributed development team.
>/**
> * Testable is abstract base class providing testing frame for classes.
> */
>class Testable : public Loggable {
> friend Tester;
Is the friend declaration needed?
> /**
> * Public method for application interal operation tests for startup.
> * @return True if check was succesfull.
> */
> virtual bool systemCheck() = 0;
If this is intended to be called only from within derived classes why
is it here? If not why isn't it being called?
> /**
> * Protected member holding the composte Tester instance.
> */
> Tester m_tester;
This isn't initialized and I don't know why anyone would want it.
>/**
> * TestTool is the static main class of Util test framework.
> */
>class TestTool : public Loggable {
> public:
> /**
> * Public method for adding tester to system.
> * @return True if tester name was unique.
> */
> static bool add(Tester *tester);
Who deletes the tester? Why isn't this class a singleton?
> private:
> /**
> * Private member map holding tester instances.
> */
> static map<string,Tester *> m_testers;
Why bother with both Tester and Testable? Can't the map hold pointers
to Testable's?
> Tester::Tester(const string &name,Testable *testable,Logger *logger) :
>Loggable(logger) {
> assert(testable);
> m_testable=testable;
> m_name=name;
> TestTool::add(this);
> }
I'm not keen on the idea of introducing a circular dependency between
Tester and TestTool nor do I think it's a good idea for lower level
classes (Tester) to know about higher level classes (TestTool).
> bool Tester::test() {
> log(m_name,"test()","Running generic test cases.");
> bool success=m_testable->test();
> if(success)
> log(m_name,"test()","Generic tests passed.");
> else
> log(m_name,"test()","Generic tests failed.");
> return success;
> }
I don't know about this. I'd use a convention where tests printed a
message as they run (eg "Starting AIEngine test"). This way you know
that the tests are actually running which is a nice confidence
builder. The above code seems like it'll generate a lot of useless
spam.
> bool Tester::stressTest() {
> /* Add memory consumption check here. */
I don't know if you guys have settled on a token for this sort of
thing, but you really need something searchable for stuff like this
(TODO, $$$, whatever).
> // Logger.clone() is needed so that Loggable instance has own
>instance.
> TestTool::TestTool(Logger *logger) : Loggable(logger->clone()) {
> }
Cloning is an awkward and inefficient way to handle this. Using a
reference counted smart pointer is probably a better way to go.
> bool TestTool::testAll() {
> map<string,Tester *>::iterator i;
> map<string,Tester *>::iterator end=m_testers.end();
>
> bool success=true;
> log("TestTool","testAll()","Running generic test cases.");
> for(i=m_testers.begin();i!=end;i++) {
> if(!((*i).second->test())) success=false;
> }
It's much more efficient to use ++i instead of i++ with the more
complex STL containers (like map). This avoids the creation of a
temporary which can make a big difference in simple loops.
> if(success)
> log("TestTool","testAll()","Generic tests passed.");
> else
> log("TestTool","testAll()","Generic tests failed.");
> return success;
> }
Why do the log messages say "Generic"? It might be a good idea to
write out the number of tests, especially for the failures.
> bool TestTool::add(Tester *tester) {
> assert(tester);
> if(m_testers.count(tester->name()))
> return false;
I find it hard to believe that anyone will check the result of
calling this method. Better to tighten up the interface and make
adding a test with a duplicate name a precondition violation, catch
it with assert, and return void.
> void TestTool::remove(Tester *tester) {
> assert(tester);
> if(m_testers.count(tester->name()))
> m_testers.erase(m_testers.find(tester->name()));
This too, should be a precondition violation. You also don't need the
call to find(): "m_testers.erase(tester->name())" will work. For that
matter, you probably don't need a map at all, especially for a
server. std::set<Tester*> would probably be better.
-- Jesse
_______________________________________________
Server mailing list
Server@...
http://mail.worldforge.org/lists/listinfo/server
|