Skip to content

Testing¤

Tests check that public Python wrappers keep working with generated protobuf messages. Mirror the source layout, reuse the enum-parity helper, and check warnings explicitly so the suite catches unwanted API changes early.

Mirror the source tree¤

Mirror src/frequenz/client/common/ under tests/, without that prefix. For example, src/frequenz/client/common/metrics/_thing.py normally becomes tests/metrics/test_thing.py. Drop the leading implementation underscore and add the test_ prefix. Keep the proto/<namespace>/ directories. Split a large source module into a matching test subdirectory when its types or functions need separate files.

Use absolute public imports in tests. This checks that supported imports work. It also stops a test from relying on an internal implementation-module path.

Reuse enum parity tests¤

For an exported enum that matches a protobuf enum, subclass EnumParityTest. Set its python_enum, proto_enum, name_prefix, from_proto, and to_proto attributes. The inherited tests check wrapper member names and numbers, known-value conversion, and unknown values. They intentionally accept generated protobuf members that the wrapper does not expose yet, so a newer protobuf API remains compatible with an older wrapper.

A protobuf API version that numbers a value differently from the wrapper enum cannot use this helper, because the parity checks compare those numbers. Write explicit tests for that version instead, pinning each generated value to the member it converts to. Enums explains when this happens.

Treat documentation and warnings as tests¤

Sybil collects Python examples in source docstrings and checks that they pass some basic linter checks. Keep each example self-contained and correct for its API. The test suite treats most warnings as errors; deprecation warnings are configured separately and should be asserted explicitly.

Assert each expected deprecation with pytest.deprecated_call(). This records the public warning and stops an unrelated warning from being hidden. When deprecated code correctly calls another deprecated symbol, suppress only that inner DeprecationWarning in a small warning block to avoid duplicate messages. In a test, use the same small suppression only for a warning that a dedicated assertion already checks. Never suppress warnings globally.