Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Test classes  (Read 2260 times)

0 Members and 1 Guest are viewing this topic.

Andrei15193

  • Guest
Test classes
« on: July 11, 2012, 12:42:07 pm »
Hello,

I've written a small UnitTest model (I know there are libraries out there that implement UnitTesting for C++, however I wanna do my own). Here is the code, the documentation within comments should be conclusive (however if it's not, please post here a reply so I can elaborate):

Tester.hpp
#ifndef TEST_TESTER_HPP
#define TEST_TESTER_HPP

#include <string>

// Contains all Tester classes including a TestAll class which runs tests on any or all classes.
namespace Test{
    // Represents the abstract model of a tester class.
    // Tester classes are used to test other, particular, classes or methods.
    class Tester{
    private:
        // Used to identify the class or method tested.
        // should have the format: test_<className>[<_methodName>].
        std::string _name;

    protected:
        // Creates a new tester with the specified name.
        Tester(const std::string& name): _name(name) { }

    public:
        // Enables polymorphic destruction of derived type instances.
        virtual ~Tester() { }

        // Runs a test, returns the number of errors.
        virtual unsigned int test() = 0;

        // Returns the test name (see _name member description).
        const std::string& getName() const {return _name;}
    };
}

#endif
 

TestShape.hpp (doesn't do any actual testing yet, just an example of a specialized Tester)
#ifndef TEST_TESTSHAPE_HPP
#define TEST_TESTSHAPE_HPP

#include "Tester.hpp"
#include "Shape.hpp"

namespace Test{
    // Represents a Tester specialized for testing the Shape class within the Tetrix::Domain namespace.
    class TestShape : public Test::Tester{
    public:
        // Creates a new Tester for testing the Shape class.
        TestShape(): Test::Tester("test_Shape") { }

        // Runs tests on the Shape and returns the number of erros for a Shape object.
        // Altho incorrect to have massive inline functions,
        // it is better to have 1 file per test function.
        virtual unsigned int test(){
            return 1;
        }
    };
}

#endif
 

TestAll.hpp
#ifndef TEST_TESTALL_HPP
#define TEST_TESTALL_HPP

#include <vector>
#include <iostream>
#include "Tester.hpp"

// Include testers here
#include "TestShape.hpp"

namespace Test{
    // Represents a special Tester, it is responsible with running tests from all available test classes.
    class TestAll : public Test::Tester{
    private:
        // Retains a vector of references to all available testers.
        std::vector<Test::Tester*> _forTests;

        // Runs a test from the Tester, returns the number of errors and
        // outputs to stdout if the test failed.
        unsigned int _test(Test::Tester* tester);

        // Outpust to stdout the name of the tester and the number of errors specified.
        void _testFailed(const Test::Tester* const tester, int errors){
            std::cout<<tester->getName()<<" failed with "<<errors<<" errors"<<std::endl;
        }

    public:
        // Creates a new TestAll instance.
        TestAll();

        // Destroies the current instance. DO NOT CALL EXPLICITLY!
        // Enables polymorphic destruction of derived type instances.
        virtual ~TestAll();

        // Runs all available tests and returns the error count.
        virtual unsigned int test();
    };
}

#endif
 

TestAll.cpp (there are 3 Testers of the same type to test the noTest array)
// Array of indexes for Testers that will not run tests.
// Index + 10 to get the line where the respective Tester is being added,
// e.g: 0 + 10 => Test::TestShape, on index 0 Test::TestShape tester is found.
// The array elements must be separated with commas or the code fails. Use -1 to test everything.
#define DO_NOT_TEST -1

#include "TestAll.hpp"

Test::TestAll::TestAll(): Test::Tester::Tester("test_TestAll"), _forTests(std::vector<Test::Tester*>()){
    _forTests.push_back(new Test::TestShape);
}

Test::TestAll::~TestAll(){
    auto end = _forTests.end();
    for (auto it = _forTests.begin(); it != end; it++)
        delete *it;
}

unsigned int Test::TestAll::test(){
    std::vector<unsigned int> noTest({DO_NOT_TEST});
    unsigned int totalErrors = 0,
                 testSize = _forTests.size(), noTestSize = noTest.size();

    for (unsigned int testIndex = 0, noTestIndex = 0; testIndex != testSize; testIndex++)
        if (noTestIndex < noTestSize && noTest[noTestIndex] == testIndex)
            noTestIndex++;
        else
            totalErrors += _test(_forTests[testIndex]);

    if (totalErrors != 0)
        _testFailed(this, totalErrors);
    return totalErrors;
}

unsigned int Test::TestAll::_test(Test::Tester* tester){
    if (unsigned int errors = tester->test() != 0){
        _testFailed(tester, errors);
        return errors;
    }
    else
        return 0;
}
 

main.cpp
#define DO_TESTS

#ifndef DO_TESTS
#include "Application.hpp"

int main(){
    Tetrix::Application app
    return app.run();
}

#else
#include "TestAll.hpp"

int main(){
    Test::TestAll testAll;
    testAll.test();
    return 0;
}

#endif
 
What do you guys think about this UnitTesting method? Is it good? Is it bad? Does it miss anything? Does it have to much of something?


[edit]
Fixed a bug in the Test::TestAll::test() for loop. The conditions at if statement were incorrect.
[/edit]
« Last Edit: July 11, 2012, 02:37:38 pm by Andrei15193 »