Hello, this more of a discussion question than a “help me with my code” question. So, get a drink, because this is a long one.
I’m going to briefly describe my project just to give some context: the project has several private libraries that are basically wrappers for Arduino libraries, for example, an HTTPClient
wrapper that prepares a message before sending it via the Arduino lib. And the project has an state machine implementation that makes calls to those wrapper libraries.
Now I want to test this project with PlatformIO provided tools. For this I’m using googletest
. I was able to create tests for the state machine using mocks for my private libraries without much problem, but I’m stuck at testing the wrapper libraries that are dependant on the Arduino libraries.
Here is an example of what I’m trying to do: in my code I have a function that does different things depending on the return value of the begin
function
//production code
#include <HTTPClient.h>
HTTPClient client;
int functionToBeTested()
{
if (client.begin("http://host.url"))
{
//do stuff
return succes_code;
}
// do other stuff
return error_code;
}
I want to create one test for the succes path and another for the error path, for that I tried to mock the begin
function like this:
// mock code
#include <gmock/gmock.h>
#include <HTTPClient.h>
class HTTPClientMock : public HTTPClient
{
public:
MOCK_METHOD(bool, begin, (String));
};
But it seems I’ve found a limitation of the googletest
framework. The problem is that gmock
is only capable of mocking virtual
functions, which is not the case for functions provided by the Arduino libraries. So now I’m not sure how to proceed.
My first question is: does the way I’m thinking about tests makes sense? I’m not very familiar with how these tests more dependant on hardwareof are usually done, so, maybe my understading is not very correct.
Second: assuming this approach is doable, how do I solve this problem with mocking non-virtual functions?
In the gtest documentation, the solution provided is Hi-perf dependency injection, but this solution involves a lot of changes in the production code, so I’m not very inclined on using it.
Another possibility would be creating a fake for each Arduino library I’m using, which provides the same functions, but not the implementation. I just don’t know exactly how I would get this to “substitute” the production code with the testing code. Is using #ifdef
macros in the productio code the usual way of doing this?
//production code
#ifdef PIO_UNIT_TESTING
#include <HTTPClient.h>
HTTPClient client;
#else
#include "myHTTPClinetFake.h"
HTTPClient fake client
#endif
Or is there a way to do the substitution at linking time by setting some variable in the platformio.ini
?
This approach leaves me with another question. Using mocks I can do EXPECT_CALL(httpClientMock, begin(String(addrBuffer))).WillOnce(Return(true));
to ensure the test will cover the path I want it to cover. How would I do that (replicate the WillOnce(Return(true))
part) with a fake implementation?
Any insigths or reading material regarding this questions are greatly appreciated.