Claude Code Plugins

Community-maintained marketplace

Feedback
4
0

Write and run tests for the python-bsblan library. Use this skill when creating unit tests, working with fixtures, or ensuring code coverage requirements are met.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name bsblan-testing
description Write and run tests for the python-bsblan library. Use this skill when creating unit tests, working with fixtures, or ensuring code coverage requirements are met.

Testing python-bsblan

This skill guides you through testing practices for the python-bsblan library.

Test Structure

Tests are located in tests/ and use pytest with async support.

Basic Test Pattern

import pytest
from bsblan import BSBLAN

@pytest.mark.asyncio
async def test_feature_name(mock_bsblan: BSBLAN) -> None:
    """Test description."""
    # Arrange
    expected_value = "expected"

    # Act
    result = await mock_bsblan.some_method()

    # Assert
    assert result == expected_value

Using Fixtures

Test fixtures (JSON responses) are in tests/fixtures/. Common fixtures:

  • device.json - Device information
  • state.json - Current state
  • hot_water_state.json - Hot water state
  • sensor.json - Sensor readings

Load fixtures using the load_fixture helper from conftest.py.

Coverage Requirements

  • Total coverage: 95%+ required
  • Patch coverage: 100% required (all new/modified code must be fully tested)

Check Coverage

# Full coverage report
uv run pytest --cov=src/bsblan --cov-report=term-missing

# Coverage for specific test file (useful during development)
uv run pytest tests/test_your_file.py --cov=src/bsblan --cov-report=term-missing --cov-fail-under=0

# HTML report for detailed analysis
uv run pytest --cov=src/bsblan --cov-report=html
# Then open htmlcov/index.html in browser

Verify New Code is Covered

After adding new methods, always verify coverage:

  1. Run tests with --cov-report=term-missing
  2. Check the "Missing" column shows no line numbers for your new code
  3. Look for uncovered branches (shown as line->branch like 382->386)

Example output showing good coverage:

src/bsblan/bsblan.py     426      0    170      2    99%   382->386, 1393->1391

The 382->386 notation means line 382's branch to line 386 isn't covered (an edge case).

GitHub Actions Coverage

CI enforces:

  • Total coverage ≥ 95%
  • Patch coverage = 100% (Codecov checks new/modified lines)

If CI fails with coverage issues, check the Codecov report in the PR for uncovered lines.

Running Tests

# Run all tests
uv run pytest

# Run specific test file
uv run pytest tests/test_bsblan.py

# Run with verbose output
uv run pytest -v

# Run specific test
uv run pytest tests/test_bsblan.py::test_function_name

Pre-commit Hooks

Always run before committing:

uv run pre-commit run --all-files

This runs:

  • Ruff: Linting and formatting (88 char line limit)
  • MyPy: Static type checking
  • Pylint: Code analysis
  • Pytest: Test execution with coverage

Mock Patterns

For API calls, use mock_bsblan fixture and verify calls:

mock_bsblan._request.assert_awaited_with(
    base_path="/JS",
    data={"Parameter": "1610", "Value": "60.0", "Type": "1"},
)

Testing Lazy Loading

When testing hot water methods, mark param groups as validated to skip network calls:

@pytest.mark.asyncio
async def test_hot_water_no_params_error(monkeypatch: Any) -> None:
    """Test error when no parameters available."""
    bsblan = BSBLAN(config, session=session)

    # Set empty cache and mark group as validated
    bsblan.set_hot_water_cache({})
    bsblan._validated_hot_water_groups.add("essential")  # Skip validation

    with pytest.raises(BSBLANError, match="No essential hot water"):
        await bsblan.hot_water_state()

For full integration tests with mocked responses:

# Mark group as validated to use cached params
bsblan._validated_hot_water_groups.add("config")
bsblan.set_hot_water_cache({"1601": "eco_mode_selection", ...})

Testing Concurrent Access

The library uses asyncio locks for race condition prevention. When testing:

  • Locks are created per-section/group automatically
  • Access _section_locks and _hot_water_group_locks dicts if needed
  • The double-checked locking pattern prevents duplicate validations
# Locks are stored in these dictionaries:
bsblan._section_locks  # {"heating": Lock(), "sensor": Lock(), ...}
bsblan._hot_water_group_locks  # {"essential": Lock(), ...}