Run Pytest
- Run a specific test file
pytest path/to/test_file.py - Run a test in it:
pytest path/to/test_file.py::test_function_name
Assert
- For integer assertions:
1
assert (1==1)
- For float assertions:
1
2
import pytest
1.0==pytest.approx(1.0)
- For numpy array assertions:
1
2
3
4
import numpy as np
array1 = np.array([1, 2, 3])
array2 = np.array([1, 2, 3])
np.testing.assert_allclose(array1, array2)
Using VSCode Debugger With Pytest
ctrl+shift+pchoosedebug tests in the current fileordebug all tests(if you want to debug all tests under a configured directory)- In my debugger, I found that I have to manually set a breakpoint before the failure point in Pytest. (I might miss an easier route to get around this)
-
At the failed test, right click, and choose debug test
pytest -s <my_test.py>seems to be executing all test modules in the current directory: this will be enforced in apyproject.tomlenvironment.
Test Fixture
The boiler plate is:
1
2
3
4
5
6
7
8
9
import pytest
@pytest.fixture
def basic_config():
return {
"batch_size": 2,
}
def test_og_positional_encoder(basic_config):
batch_size = basic_config["batch_size"]
...
Patching
Patching a Function
To patch my_func() from MyModule, pytest requires it to be a MagicMock object. This means we must specify return_value and pass mock_my_func into the test function.
1
2
3
4
5
6
7
8
from unittest.mock import patch
import requests
@patch('MyModule.my_func', return_value=my_func_patch())
def test_get_license_hash(mock_my_func):
"""Test if the server responds with 200 OK."""
response = requests.get(f"{SERVER_URL}/GetLicenseHash")
assert response.status_code == 200
Patching a Constant or List
Unlike functions, patching constants or lists does not require a MagicMock. Instead, patch directly replaces the original object with a real one, meaning no return_value or mock object argument is needed.
1
2
3
4
5
@patch('MyModule.WEBCAM_RESTART_COMMAND', ["echo", "hello"])
def test_webcam_restart():
"""Test if the webcam restart command is patched correctly."""
response = requests.get(f"{SERVER_URL}/RestartService")
assert response.status_code == 200
Configure Pytests
In conftext.py, you can add a fixture to find float_dtype
1
2
3
@pytest.fixture(scope="session")
def float_dtype(request):
return torch.float16 if request.config.getoption("--fp16") else torch.float32
Then, pytest will automatically inject this fixture if you test has it:
1
def test_gathering_forward_output_shape(float_dtype):
Pylint
The duplicate-code warning is expected here. Pylint rule R0801 is triggered because several files contain nearly identical ROS 2 boilerplate. For example, the main() stubs in _compressor_node.py and _decompressor_node.py are very similar, and the same is true for the two launch files. You see this pattern across much of the codebase—such as knowledge_base and kb_visual_tools—because ROS 2 node setup naturally repeats. Unless we want to factor that boilerplate into a shared helper module, suppressing this warning is the practical choice.
Pylint’s duplicate-code check is purely textual. It compares all files passed to pylint in a single run and reports when the number of consecutive identical lines between two files exceeds its threshold (four lines by default). It does not consider whether the repeated code is simple, intentional, or idiomatic.
So if two files both contain something like:
```python rclpy.init(args=args) node = None try: node = SomeNode() rclpy.spin(node)