1

I have a template library which uses CRTP

// Base configuration to be derived from.
struct TemplateBaseConfig {
    static constexpr auto config_1 = true;
    static constexpr auto config_2 = false;
    static constexpr auto config_val_3 = 42;
};

template <typename Derived_, typename DerivedConfig_, typename... Widgets>
struct TemplateBaseClass {
    std::tuple<Widgets...> widgets;
    // Lots of functions and logic etc.
    void function_1() {
        if constexpr (DerivedConfig_::config_1) {
            // do something
        }
        static_cast<Derived_*>(this)->function_2();
    }
    void function_2() { /*do something*/ }
};

Now the user uses TemplateBaseClass as:

// Make a custom config.
struct DerivedConfig : TemplateBaseConfig {
    static constexpr auto config_1 = false;
};

struct DerivedClass : TemplateBaseClass<DerivedClass, DerivedConfig, Widget1, Widget2> {
    void function_2() { /* override base logic */ }
};

I write unittests for TemplateBaseClass by inheriting a MockTemplateBaseClassInterface.

template <typename TestingClass, typename TestingClassConfig, typename... W>
struct MockTemplateBaseClassInterface : TemplateBaseClass<TestingClass, TestingClassConfig, W> {
    // Mock some internal functions which always need to be mocked.
    MOCK(internal_function_1);
    MOCK(internal_function_2);
    // Some custom setup for unittests like override the log dir
    void function_2() { Parent::function_2(); MakeLogDir(); } // Parent is this guy's base class.
}

To write unittests for a given DerivedConfig, hence i create a derived class from MockTemplateBaseClassInterface:

ClassToTestFunction1 : MockTemplateBaseClassInterface<ClassToTestFunction1, TestConfig1, MockWidget> {
    // Write more mock functions if required.
    MOCK(function3);
};

Then I use ClassToTestFunction1 in a fixture class to write unittests.

This works flawless to test anything for TemplateBaseClass because i can given any configuration, write my own mocks when required.

Now if I have to expose this testing framework for the end user so that he can write tests for DerivedClass, what should be the way forward?

I can ask the user to do something like:

    struct DerivedClass :
#ifdef _DOING_TESTING_
 MockTemplateBaseClassInterface<DerivedClass, DerivedConfig, Widget1, Widget2> 
#else
 TemplateBaseClass<DerivedClass, DerivedConfig, Widget1, Widget2>
#endif
 {
        void function_2() { /* override base logic */ }
    };

But now the user cannot really mock TemplateBaseClass's functions.

The user would want to test his function_2(). But if function_2() uses some function of TemplateBaseClass he would want to mock it. I mean, that's the whole point of unittests right?

themagicalyang
  • 2,493
  • 14
  • 21

0 Answers0