Namespace vs Struct / Class / Etc, in regards to mocking and microcontrollers

157 Views Asked by At

I'm building a high performance C++ project on the ESP32 microcontroller. I have a number of different parts of my codebase that interact with each other and I'm writing tests for them.

I've started using the Catch2 testing framework lately, and I've been trying to get the FakeIt mocking framework to be useful for me.

The thing is, a lot of the components in my codebase are structured like this...

Data.h

// I'm using my header files to define a namespace that other files will
// load to use the API handles of this component.
namespace DataAPI {
  extern void saveTheThing(void);
  extern void loadTheThing(void);
}

Data.cpp

// I'm using my Data.cpp file to populate those API methods, as well as to store
// the private data that the component will use.

#include "Data.h"

namespace DataAPI {
  the_thing_t myDataRecord;

  void saveTheThing(void) {
    //...saves `myDataRecord` to flash.
  }

  void loadTheThing(void) {
    //...loads data from flash into `myDataRecord`
  }
}

SomeOtherComponent.cpp

#include "Data.h"

void theFunctionImGoingToTest(void) {
  DataAPI::loadTheThing();
}

This is all working great for me, but all the mocking frameworks seem to want me to be using structs or classes or something, and mocking member methods of those structs or classes. For instance...

From the FakeIt mock framework's docs...

// Here's how FakeIt suggests you set up a mock
Mock<SomeInterface> mock;
// Stub a method to return a value once
When(Method(mock,foo)).Return(1); 

This doesn't work for me because a function in a namespace can't be referred to that way.

I could do some kind of refactor of my codebase, but for the most part I don't need multiple instances of what's in these namespaces. I don't want to pay a higher memory overhead or a CPU cost.

How can I keep the singular instance of my library structure while getting to a structure that will allow me to work with mocking frameworks?

Is there a mocking framework that can work with someNamespace::someBareFunction() style code? Or is there a way I can refactor this structure in such a way that it won't introduce much bloat?

Thanks!

1

There are 1 best solutions below

0
On

Do you need a mocking framework? Mocking frameworks use classes because the goal is usually to (polymorphically) replace certain classes you use, but from which you would like to isolate your tests. The usual examples are external dependencies, like connections to web servers or databases.

I also use Catch2 for my own code, though without mocking frameworks. My Catch2 test for your code would probably start like this:

#include <SomeOtherComponent.h>
#include <catch2/catch_test_macros.hpp>

TEST_CASE("theFunctionImGoingToTest") {
    theFunctionImGoingToTest();

    // Various CHECK/REQUIRE assertions on the observable results of
    // this function call
}

Would that not be sufficient?