Skip to main content

A mock utility for testing serial devices

Project description

mock_serial

A mock utility for testing serial devices.

Credit to Dolf Andringa for the technique. 🏆

Install

pip install mock_serial

Note: this package does not work on Windows.

Usage

First setup a basic session with a MockSerial device.

from mock_serial import MockSerial

device = MockSerial()
device.open()

from serial import Serial
serial = Serial(device.port)

...

serial.close()
device.close()

Alternatively, a pytest fixture is included automatically.

from serial import Serial

def test_example(mock_serial):
  serial = Serial(device.port)

  ...

  serial.close()

.stub()

Use the .stub() method to simulate device behaviour.

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

...

serial.write(b'123')
assert serial.read(3) == b'456'

assert stub.called
assert stub.calls == 1

You can also give your stub a name for easy retrieval.

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

...

assert device.stubs['foo'].called

stub() can simulate a variety of device behaviours:

  • Lazy matching. MockSerial will defer sending a response until only one stub could match. This can be useful if certain byte sequences are ambiguous e.g. if another stub had receive_bytes = b'123456' then MockSerial will wait until it can rule out matching the "longer" stub in future.

  • Partial matching. MockSerial doesn't need to match all the data it's read in one go. This can be useful if your code or library doesn't wait for replies e.g. b'123' followed quickly by b'456' may be received as b'123456', but will be correctly matched if there are stubs for them both.

Note: you must ensure there is a stub to match each part of the byte sequence, otherwise MockSerial will stop responding. MockSerial does not support "regex" or "placeholder" matching.

Advanced

MockSerial supports overriding stubs by name or receive_bytes. This can be useful if you want to define most of your stubs once, but override the send_bytes for one or two of them in specific tests.

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

...

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

serial.write(b'123')
assert serial.read(3) == b'789'

Stubs can also return a dynamic response by passing a send_fn instead of send_bytes. The function should accept a single argument: the number of times the stub has been called, including the current call.

device.stub(
  receive_bytes=b'123',
  send_fn=lambda n: bytes(str(n), encoding='utf-8') + b'23'
)

serial.write(b'123123')
assert serial.read(6) == b'123223'

Debugging

MockSerial has lots of DEBUG logs so you can see what it's doing. It may also log a warning if it has trouble closing. This can be helpful if you're trying to debug how it's interacting with your code.

import logging, sys

logging.basicConfig(
  stream=sys.stdout,
  level=logging.DEBUG,
  format="%(levelname)s - %(message)s"
)

...

This is a rough example of what the logs look like.

DEBUG - Attached to mock serial port.
DEBUG - Buffer read: b'123'.
DEBUG - Potential matches: [b'1234' => b'456', b'1235' => fn()].
DEBUG - Buffer read: b'12341235'.
DEBUG - Match stub: b'1234' => b'456'.
DEBUG - Buffer write: b'456'.
DEBUG - Match stub: b'1235' => fn().
DEBUG - Buffer write: b'123'.
DEBUG - Detaching mock serial port.
DEBUG - Buffer read: b'mockserialquit'.
DEBUG - Detached mock serial port.
DEBUG - Closing mock serial port.
DEBUG - Closed mock serial port.

As you can see, MockSerial sends itself a special control sequence when closing. This signals to the worker thread to detach from the mock serial port, which is (sometimes) necessary in order to close it.

Contributing

See CONTRIBUTING.md.

Licence

See LICENCE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mock_serial-0.0.1.tar.gz (5.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mock_serial-0.0.1-py3-none-any.whl (6.1 kB view details)

Uploaded Python 3

File details

Details for the file mock_serial-0.0.1.tar.gz.

File metadata

  • Download URL: mock_serial-0.0.1.tar.gz
  • Upload date:
  • Size: 5.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.6.0 importlib_metadata/4.8.2 pkginfo/1.8.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

File hashes

Hashes for mock_serial-0.0.1.tar.gz
Algorithm Hash digest
SHA256 9c92de7495ac375717bbbeb4993534079d2e634f3298d4c400420c4046add06e
MD5 64f472ad4d882dccaf4c9786b39a0c2f
BLAKE2b-256 c6d9b9ec64510ffb4bccd7491c4583b8f24732ed4af6311c621822c3a9e47b46

See more details on using hashes here.

File details

Details for the file mock_serial-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: mock_serial-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 6.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.6.0 importlib_metadata/4.8.2 pkginfo/1.8.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

File hashes

Hashes for mock_serial-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b6b8cc10c302354bf3ca270a3d4d6bf199c4bbe41478c65046db8f30ea967675
MD5 ac0d4d32ed25214ba351f01313b481c9
BLAKE2b-256 98c28c1e6bf77cf62a10203a107179e34e0965fc5369386e0b7034a247ed054d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page