Skip to content

Commit 1beb9e7

Browse files
pi-anlgemini-2.5-pro-exp-03-25
andcommitted
docs: Improve documentation for writing and running tests
Reviewed the run-tests.py and run-multitests.py scripts and used the insights to significantly enhance the documentation in docs/develop/writingtests.rst. The updated documentation provides: - More detailed explanation of the test directory structure and key runner scripts. - Clearer instructions on writing simple tests, including the use of print() and .exp files. - Expanded coverage of run-tests.py options for targeting specific devices, filtering tests, and handling failures. - An overview of how run-tests.py works internally (feature detection, skipping, execution, comparison). - Guidance on writing advanced tests (skipping, unittest, special handling, float/endian considerations). - Introduction to multi-instance testing with run-multitests.py, including how to write tests with instanceN() functions and use the `multitest` helper for coordination. - Examples of running multi-instance tests with different instance types. 🤖 Generated with gemini-2.5-pro-exp-03-25 Co-Authored-By: gemini-2.5-pro-exp-03-25 <[email protected]>
1 parent ef8282c commit 1beb9e7

File tree

2 files changed

+370
-233
lines changed

2 files changed

+370
-233
lines changed

docs/develop/writingtests.rst

Lines changed: 204 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,68 +3,233 @@
33
Writing tests
44
=============
55

6-
Tests in MicroPython are located at the path ``tests/``. The following is a listing of
7-
key directories and the run-tests.py runner script:
6+
MicroPython's test suite resides in the ``tests/`` directory. It's crucial for ensuring code correctness and stability across various ports and hardware.
87

9-
.. code-block:: bash
8+
Overview of the Test Suite
9+
--------------------------
10+
11+
The MicroPython test suite consists of multiple components:
12+
13+
1. **Standard Tests**: The majority of tests that run on a single instance and verify functionality against CPython or expected outputs.
14+
2. **Multi-instance Tests**: Tests that require multiple MicroPython instances to interact with each other (e.g., networking, Bluetooth).
15+
3. **Native Module Tests**: Tests for dynamic native modules compiled to ``.mpy`` files.
16+
4. **Performance Benchmarks**: Python-level benchmarks for measuring execution speed.
17+
5. **Internal Benchmarks**: Low-level benchmarks for core VM operations and C code.
18+
19+
This document primarily focuses on the standard tests and multi-instance tests.
20+
21+
Directory Structure
22+
------------------
23+
24+
The ``tests/`` directory is organized into subfolders by functionality:
25+
26+
* ``basics/``: Core Python language features
27+
* ``extmod/``: Extended modules (like ``ujson``, ``ure``)
28+
* ``float/``: Floating-point arithmetic specifics
29+
* ``micropython/``: MicroPython-specific features and behaviors
30+
* ``import/``: Import mechanisms
31+
* ``io/``: Input/Output operations
32+
* ``stress/``: Tests designed to push resource limits (memory, recursion)
33+
* ``thread/``: Threading module tests
34+
* ``cmdline/``: Tests for the command-line interface and REPL
35+
* ``ports/<port_name>/``: Tests specific to a particular port
36+
* ``feature_check/``: Scripts used to detect target capabilities
37+
* ``multi_bluetooth/``, ``multi_network/``: Tests involving multiple instances
38+
* ``perf_bench/``: Performance benchmarking scripts
39+
* ``internal_bench/``: Low-level internal benchmarks
1040

11-
.
12-
├── basics
13-
├── extmod
14-
├── float
15-
├── micropython
16-
├── run-tests.py
17-
...
41+
Key Test Runner Scripts:
1842

19-
There are subfolders maintained to categorize the tests. Add a test by creating a new file in one of the
20-
existing folders or in a new folder. It's also possible to make custom tests outside this tests folder,
21-
which would be recommended for a custom port.
43+
* ``run-tests.py``: Main script for standard tests
44+
* ``run-multitests.py``: For tests requiring multiple interacting instances
45+
* ``run-natmodtests.py``: For testing dynamic native modules
46+
* ``run-perfbench.py``: For performance benchmarks
47+
* ``run-internalbench.py``: For low-level internal benchmarks
2248

23-
For example, add the following code in a file ``print.py`` in the ``tests/unix/`` subdirectory:
49+
Writing Standard Tests
50+
---------------------
51+
52+
Standard tests are the most common type. They verify functionality by comparing output against expected results.
53+
54+
1. **Choose a Directory:** Select the appropriate subfolder for your test based on the functionality it tests.
55+
2. **Create a ``.py`` file:** Add your test code to a new Python file.
56+
3. **Use ``print()``:** The test harness works by comparing standard output. Use ``print()`` statements to output results.
57+
4. **Expected Output:**
58+
* **CPython Comparison:** By default, tests are run on both CPython and MicroPython with outputs compared.
59+
* **``.exp`` Files:** For MicroPython-specific features, create a ``<testname>.py.exp`` file with the expected output.
60+
61+
Example:
62+
63+
Create ``tests/basics/simple_print.py``:
2464

2565
.. code-block:: python
2666
27-
def print_one():
28-
print(1)
67+
# tests/basics/simple_print.py
68+
print("Hello")
69+
a = 1 + 2
70+
print(a)
71+
72+
When run, MicroPython's output will be compared to CPython's output (or ``simple_print.py.exp`` if it exists).
73+
74+
Types of Tests
75+
-------------
2976

30-
print_one()
77+
The test system supports three main testing approaches:
3178

32-
If you run your tests, this test should appear in the test output:
79+
1. **CPython comparison tests**:
80+
* Used for behavior that should match CPython
81+
* Tests are run on both CPython and MicroPython
82+
* Passes if outputs match exactly
83+
84+
2. **Expected output (``.exp``) tests**:
85+
* Used for MicroPython-specific features or when CPython behavior differs
86+
* MicroPython output is compared against contents of a ``.py.exp`` file
87+
* Passes if outputs match exactly
88+
89+
3. **``unittest``-based tests**:
90+
* Requires ``unittest`` module to be available on the target
91+
* Used for hardware testing or other MicroPython-specific behavior
92+
* Passes if unittest summary shows "OK"
93+
94+
Running Tests (``run-tests.py``)
95+
--------------------------------
96+
97+
The primary script is ``run-tests.py``, executed from the ``tests/`` directory.
98+
99+
**Basic Usage:**
33100

34101
.. code-block:: bash
35102
36-
$ cd ports/unix
37-
$ make tests
38-
skip unix/extra_coverage.py
39-
pass unix/ffi_callback.py
40-
pass unix/ffi_float.py
41-
pass unix/ffi_float2.py
42-
pass unix/print.py
43-
pass unix/time.py
44-
pass unix/time2.py
103+
# Run default tests for the Unix port
104+
cd tests/
105+
./run-tests.py
106+
107+
**Running on Hardware Targets:**
45108

46-
Tests are run by comparing the output from the test target against the output from CPython.
47-
So any test should use print statements to indicate test results.
109+
.. code-block:: bash
110+
111+
# Run on a specific serial port
112+
./run-tests.py -t /dev/ttyACM0
113+
./run-tests.py -t COM3
48114
49-
For tests that can't be compared to CPython (i.e. micropython-specific functionality),
50-
you can provide a ``.py.exp`` file which will be used as the truth for comparison.
115+
# Use shortcuts for common serial ports
116+
./run-tests.py -t a0 # Maps to /dev/ttyACM0
117+
./run-tests.py -t u1 # Maps to /dev/ttyUSB1
118+
./run-tests.py -t c3 # Maps to COM3
51119
52-
The other way to run tests, which is useful when running on targets other than the Unix port, is:
120+
**Filtering Tests:**
53121

54122
.. code-block:: bash
55123
56-
$ cd tests
57-
$ ./run-tests.py
124+
# Run all tests in specific directories
125+
./run-tests.py -d basics
126+
./run-tests.py -d extmod -d float
127+
128+
# Run specific files
129+
./run-tests.py basics/int*.py
130+
./run-tests.py float/float_parse.py
131+
132+
# Filter by regex
133+
./run-tests.py -e viper # Exclude tests matching 'viper'
134+
./run-tests.py -i asyncio # Include only tests matching 'asyncio'
135+
136+
**Other Useful Options:**
137+
138+
* ``--emit {bytecode | native | viper}``: Run tests using a specific code emitter
139+
* ``--via-mpy``: Compile tests to ``.mpy`` files first before running
140+
* ``-j N`` or ``--jobs N``: Run N tests in parallel (for PC targets)
141+
* ``--print-failures``: Show the diff for tests that failed in the last run
142+
* ``--run-failures``: Re-run only the tests that failed in the last run
143+
* ``--clean-failures``: Remove the ``.exp`` and ``.out`` files from failures
58144

59-
Then to run on a board:
145+
How The Test System Works
146+
------------------------
147+
148+
1. **Target Detection:** Determines the platform and architecture.
149+
2. **Feature Detection:** Identifies capabilities of the target MicroPython build.
150+
3. **Test Selection:** Gathers test files based on command-line arguments or defaults.
151+
4. **Skipping Tests:** Excludes tests based on:
152+
* Command-line filters
153+
* Missing features
154+
* Platform-specific skip lists
155+
* Emitter type restrictions
156+
* Tests explicitly printing ``SKIP``
157+
5. **Execution:**
158+
* PC targets: Runs MicroPython as a subprocess
159+
* Board targets: Uses ``pyboard.py`` to connect via serial/network
160+
6. **Output Comparison:** Compares target's output with expected output
161+
7. **Reporting:** Shows results and summarizes pass/fail statistics
162+
163+
Writing Advanced Tests
164+
---------------------
165+
166+
**Skipping Tests Conditionally**
167+
168+
If a test needs to skip itself conditionally:
169+
170+
.. code-block:: python
171+
172+
import sys
173+
if not hasattr(sys, 'feature_needed'):
174+
print('SKIP')
175+
sys.exit()
176+
177+
**Special Test Handling**
178+
179+
Some tests need special options:
180+
181+
* Add comments in the test file: ``# cmdline: -X heapsize=...``
182+
* Tests needing redirection are listed in ``special_tests`` in ``run-tests.py``
183+
184+
**Platform Considerations**
185+
186+
* **Floating Point:** Be mindful of precision differences. Use ``math.isclose()`` with appropriate tolerances.
187+
* **Endianness:** Check ``sys.byteorder`` for byte order sensitive operations.
188+
* **Memory/Stack:** Avoid large allocations or deep recursion on constrained devices.
189+
190+
Multi-instance Tests
191+
-------------------
192+
193+
For testing interactions like networking or Bluetooth, ``run-multitests.py`` orchestrates multiple instances.
194+
195+
**Writing Multi-instance Tests:**
196+
197+
1. Define functions named ``instance0()``, ``instance1()``, etc. for each instance's code.
198+
2. Use the ``multitest`` helper for coordination:
199+
* ``multitest.next()``: Complete a stage and wait for other instances
200+
* ``multitest.broadcast(msg)``: Send a message to all other instances
201+
* ``multitest.wait(msg)``: Wait for a specific broadcast message
202+
* ``multitest.skip()``: Indicate the test should be skipped
203+
* ``multitest.globals(var=value, ...)``: Set global variables
204+
* ``multitest.get_network_ip()``: Get the IP address
205+
* ``multitest.expect_reboot(resume_func_name, delay_ms)``: Handle device reboots
206+
207+
**Running Multi-instance Tests:**
60208

61209
.. code-block:: bash
62210
63-
$ ./run-tests.py -t /dev/ttyACM0
211+
# Run a network test using two unix instances
212+
./run-multitests.py -i micropython -i micropython multi_network/tcp_connect.py
213+
214+
# Run a bluetooth test using two pyboards
215+
./run-multitests.py -i pyb:/dev/ttyACM0 -i pyb:/dev/ttyACM1 multi_bluetooth/ble_connect.py
64216
65-
And to run only a certain set of tests (eg a directory):
217+
Provide as many ``-i`` arguments as instances required by the tests.
218+
219+
Test Certificates for SSL/TLS Tests
220+
----------------------------------
221+
222+
Network tests using SSL/TLS require test certificates to be available on the device. These certificates are included in the repository in ``multi_network/`` and ``net_inet/`` directories.
223+
224+
**Preparing a Device for SSL/TLS Tests:**
225+
226+
Use ``mpremote`` to set the device's RTC and copy the certificate files:
66227

67228
.. code-block:: bash
68229
69-
$ ./run-tests.py -d basics
70-
$ ./run-tests.py float/builtin*.py
230+
# From the micropython/tests/ directory:
231+
mpremote rtc --set cp multi_net/*.der net_inet/*.der :/
232+
233+
This sets the device's Real Time Clock (using the host's time) and copies all ``.der`` files to the root directory of the device's filesystem.
234+
235+
These certificates are self-signed and generated for testing purposes only.

0 commit comments

Comments
 (0)