shimo4228

mock-friendly-api-layering

"Use when mock assertions fail due to public functions forwarding internal params like url or timeout to a shared helper."

shimo4228 1 Updated 3mo ago
GitHub

Install

npx skillscat add shimo4228/claude-code-learned-skills/mock-friendly-api-layering

Install via the SkillsCat registry.

SKILL.md

Mock-Friendly API Layering

Extracted: 2026-02-11
Context: AnkiConnect client (anki_connect.py) — public functions forwarding url to internal _invoke broke mock assertions.

Problem

When public functions forward internal routing parameters (like url, timeout, base_path) to a low-level helper, tests that mock the helper fail on assert_called_once_with() because of unexpected kwargs.

# BAD: ensure_deck forwards url to _invoke
def ensure_deck(name: str, *, url: str = ANKICONNECT_URL) -> None:
    _invoke("createDeck", url=url, deck=name)

# Test expects:
mock.assert_called_once_with("createDeck", deck="pdf2anki::test")
# Actual call:
# _invoke("createDeck", url="http://127.0.0.1:8765", deck="pdf2anki::test")
# → AssertionError: unexpected kwarg url

Solution

Keep internal routing parameters only on the lowest-level function (_invoke). Public functions expose only business-relevant parameters.

# GOOD: public function has no url param
def ensure_deck(name: str) -> None:
    _invoke("createDeck", deck=name)

# _invoke owns the url default internally
def _invoke(action: str, *, url: str = ANKICONNECT_URL, **params: Any) -> Any:
    ...

Design Principle

Layer Owns Example
_invoke (internal) Transport: url, timeout, headers _invoke("action", url=..., **params)
Public functions Business params only ensure_deck(name), push_cards(cards, deck_name=...)

When to Use

  • Wrapping HTTP APIs (AnkiConnect, REST, GraphQL) with an internal _invoke / _request helper
  • Any module with a low-level helper + multiple public functions that delegate to it
  • When mock.assert_called_once_with() fails due to extra kwargs from defaults