I wrote a small library for async detection of button events in a no_std environment: async-button. It's build around embedded-hal traits and embassy-time.
In my manual testing it works as intended but I would like to write some automated tests to be able to test edge cases that are difficult to trigger my manually pushing a button.
As you can see in lib.rs all the logic worth testing occurs in the update function. This probably makes it harder to test but I don't see a logical way to split it in smaller parts.
The logic heavily depends on timeouts and delays and I would need to somehow simulate that to trigger different outputs. How can I do that?
What I ended up doing is using #[cfg(test)] to switch between embassy-time and equivalent tokio functions. I then used a modified version of embedded-hal-mock to mock the embedded-hal traits and artificially delay the async functions from embedded_hal_async::digital::Wait so it would trigger the timeouts. This leads to test code like this:
I'm not super happy about this approach because I find the test code pretty hard to understand. Also, implementation details of the test code leak into the main library code. I'd be happy to hear if there are better ways to do this this.