Skip to content

Conversation

@aliberts
Copy link

@aliberts aliberts commented Mar 22, 2025

Motivation

In some situations, a test might be checking if a stub has been called before MockSerial thread had time to read, match, and call the stub. In these situations, the test can fail randomly.

Changes

Adds two optional synchronization methods to the Stub class:

  • wait_called(timeout: float = 1.0): Blocks until the stub is called at least once.
  • wait_calls(min_calls: int = 1, timeout: float = 1.0): Blocks until the stub has been called min_calls times.

Usage

stub = device.stub(
  receive_bytes=b'123',
  send_bytes=b'456'
)

...

# wait until the stub is called at least once
assert device.stubs['foo'].wait_called()

# or wait until it's called a specific number of times
assert device.stubs['foo'].wait_calls(min_calls=3) == 3

Also just wanted to say: thank you for this package! solved a lot of my problems to test hardware-related code 🙏

@benthorner
Copy link
Owner

Great to hear this has been useful 🙂. And thanks for suggesting this feature.

In some situations, a test might be checking if a stub has been called before MockSerial thread had time to read

I'm guessing this is when the code under test doesn't wait for a response from the device. Is that right?

Adds two optional synchronization methods to the Stub class

I agree this would solve the problem. However, it's somewhat beyond the scope of this library: just a mocking a device. While we could extend the scope, I wonder if you've come across libraries like tenacity?

Example of waiting using Tenacity:

from tenacity import Retrying, RetryError, stop_after_attempt

for attempt in Retrying(stop=stop_after_attempt(3)):
    with attempt:
        # wait until the stub is called at least once
        assert device.stubs['foo'].called
        
        # or wait until it's called a specific number of times
        assert device.stubs['foo'].calls == 3

This is a bit clunky, but could be simplified with a quick helper function. Or using a different "retry" library: Tenacity is just the one I'm familiar with; other libraries I've tried have some flaws if I recall correctly.

One advantage of this approach is that it separates the mocking concern from the waiting concern, allowing both features to be iterated independently. If it would work for you, perhaps we can recommend it in the README.

What do you think?


Appreciate the effort to make a PR, by the way. I'd like to explore the option above before reviewing in detail.

Apologies in advance: my time for personal projects is very limited; a response may be delayed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants