There are at least two different kinds of testing that may be applicable.
One is on-device or end-to-end testing by flashing firmware to the device and observing behavior, with or without automation.
The other is unit testing, often done off-device in your native environment as part of test-driven-design (TDD).
An example of unit testing can be found in the communication library for Device OS. This is a good example of where unit testing of the communication layer can test various edge cases. The code is in Github. This module uses UnitTest++ as the test framework.
Another framework that is used is Catch2. The Device OS tests using Catch2 are here.
Finally, you can do it manually. That’s what I did for JsonParserGeneratorRK. Look in the test directory. It builds the library core using the native gcc compiler and runs tests. This is particularly useful under Linux as you can also run it under valgrind, which can detect memory leaks and block overruns.
If you are using testing tools I would just not use .ino files at all. They are .cpp files that automatically
#include "Particle.h"
and generate forward declarations for functions used before they are implemented. It’s better to just write the proper .cpp files which can be more easily processed by standard tools like native gcc.
Just rename your main source from from .ino to .cpp, add the include, and any forward declarations if you need them. Workbench and the CLI cloud compilers work fine only using .cpp files.