Search code examples
c++visual-c++cppunitmicrosoft-cpp-unit-test

How to initialize test variables using Visual Studio CppUnitTestFramework


I'm writing a roboter controller class Controller in which I'm using a struct Axis for each of the 4 controllable motors.

For each test I want to reset everything, so I created a pointer in the class which is changed to a new Controller before each test method. The initialisation works fine in TEST_METHOD_INITIALIZE, but once any TEST_METHOD is called the program seems reset the Axis pointers.

Thanks for your help!

Edit: After further analysis I have the theory, that the initialised Axis objects Axis init_mx are deleted after the method is finished.

Edit2: I think this a slightly more complex problem like this: Pointer to local variable in C++ Nevertheless, I didn't find a way to reset the Axis variables at for every method without actually resetting each variable in it.

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
...
namespace UnitTest
{

    TEST_CLASS(UnitTestController)
    {
    public:
        Controller* controller;
        struct Axis *mx, *my, *mz, *mg;

        TEST_METHOD_INITIALIZE(methodName)
        {
            Axis init_mx(50), init_my(50), init_mz(50), init_mg(5);         
            mx = &init_mx;
            my = &init_my;
            mz = &init_mz;
            mg = &init_mg;
            Controller init_controller(mx, my, mz, mg);
            controller = &init_controller;

enter image description here

        }
        ...
        TEST_METHOD(id_3_next_mode)
        {
            mx->position = 5; 
            controller->getAxisPositionMx();              
            //Axis in pointers got reset and therefore have no pointers to the 
            //provided structs from TEST_METHOD_INITIALIZE

        }

        }

    };
}

enter image description here Controller.h(excerpt):

private:
struct Axis *mx, *my, *mz, *mg;

Controller.cpp (excerpt)

Controller::Controller(Axis *mx_in, Axis *my_in, Axis *mz_in, Axis *mg_in)
{
    mx = mx_in;
    my = my_in;
    mz = mz_in;
    mg = mg_in;
}

Solution

  • You found your original bug, but I think it's worth pointing out some details of how test modules, classes, methods, and the special initialize/cleanup methods are intended to work.

    The most important thing to note is that a new instance of the class is instantiated every time a test method is executed, so each test will have a fresh set of class variables. This means that your example test class could look like:

    TEST_CLASS(UnitTestController)
    {
    public:
        struct Axis mx, my, mz, mg;
        Controller controller;
    
        // Define a constructor to initialize the class variables
        UnitTestController() : 
            mx(50), my(50), mz(50), mg(50),
            controller(mx, my, mz, mg)
        {
        }
    
        TEST_METHOD(id_3_next_mode)
        {
            mx.position = 5; 
            controller.getAxisPositionMx();              
        }
    };
    

    If you wanted to have a variable persist between tests, you could put it outside the test class.

    namespace UnitTest {
    
        SomeClass moduleVar1;
    
        TEST_CLASS(UnitTestClass)
        {
        public:
    
            TEST_METHOD(TestMethod1)
            {
               Assert::IsTrue(moduleVar1.SomeMethod());
            }
    
            TEST_METHOD(TestMethod2)
            {
               Assert::IsFalse(moduleVar1.SomeOtherMethod());
            }
        };
    } 
    

    The framework also provides the following Initialize and Cleanup functions which can be used to manipulate the test environment and fixtures:

    • TEST_METHOD_INITIALIZE - Called once before running each test method.
    • TEST_METHOD_CLEANUP - Called once after running each test method.
    • TEST_CLASS_INITIALIZE - Called once per module before running any tests belonging to this class.
    • TEST_CLASS_CLEANUP - Called once per module after running all tests belonging to this class.
    • TEST_MODULE_INITIALIZE - Called once per module before running any tests or class initalizers.
    • TEST_MODULE_CLEANUP - Called once per module after running all tests and class cleanups.