I am writing a driver for an IMU sensor using test driven development approach. Communication protocol of choice is SPI. Using CubeMX and STM32F415 processor, SPI interface is implemented in stm32f4xx_hal_spi.h file, which contains many and more function declarations. Note this SPI interface is processor-specific and IMU driver may also be implemented on different platforms so flexibility is also important.

For test driven development needs I have to mock SPI functions I use within driver code. I came up with two possible options:

1) Original SPI header file stm32fxx_hal_spi.h is included directly into driver header. Its entire contents gets mocked, even though only very few functions are acutally used in sensor driver.

PRO

  • straightforward implementation

CON

  • actual SPI driver files have to be copied into sensor driver project
  • mocking fat interface


2) Within driver project create spi.h header. Re-declare functions that are used by driver but are originally already declared in stm32fxx_hal_spi.h . Mocking spi.h gives mocks only for functions actually used.

PRO

  • no need to copy processor-specific SPI driver files into sensor driver project

  • mock only things used

CON

  • test driving seems straightforward but am unsure how to integrate with hardware and stm32fxx_hal_spi.h file

It seems to me that second approach does a better job in terms of abstracting spi implementation into a single header file. But as mentioned, I am unsure how to proceed to link this to actual spi driver files during integration of sensor driver into entire project.

Is any of these considered a valid approach? Is there a generally accepted approach for this during driver development?

I suggest using a conventional object oriented approach. Even with plain C code, this is fairly easy.

struct spiInterace {
   void* privateData;
   void eachFunctionInSPIInterface();..
};
typedef struct spiInterace  spiInterace ;

Then your real SPI interface provides a 'new function':

spiInterace* mkstm32f4xx_hal_spi()
{
   // malloc object, add any needed private data pointer (like
   // to memory mapped or open file descriptor) and fill in
   // function pointers to APIs now moved to static functions
}

... Similarly for your 'mock' SPI device driver.

Change all your calls to indirect through the spiIntrface object:

   spiInterface* spiI = // call one mkFunction or the other for testing or real;
   // instead of earlier call to eachFunctionInSPIInterface(someSPIdesignator);
   spiI->eachFunctionInSPIInterface (); 

Then testing is easy - just construct one or the other spiInterface.

Hope that helps!

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.