refactor(tests): one definition each for the copied fixtures and fakes (#2825, milestone 296 area 1)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 24s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 54s
CI & Build / Build & push image (push) Successful in 18s

The shape ledger showed the same test scaffolding defined over and over:
_bind_user x12 (byte-identical), _dispose_engine x10 in three wordings,
_no_supersession x3, _make_mock_session x7 in three subsets, a get-or-create
User helper x2 (+3 inlined), and fifteen hand-rolled MagicMock note factories
each re-explaining the same "an auto-MagicMock attribute is truthy" hazard
(note 2109).

Now: conftest.py carries _bind_user / _dispose_engine / _no_supersession as
opt-in fixtures (pytestmark = usefixtures(...) per module, so unit tests pay
nothing), and tests/helpers.py carries make_mock_session(), ensure_user() and
fake_note(**attrs) — the hazard documented once, real values on every
attribute the product reads. Call sites were rewritten by AST so titles with
dashes and commas survived; the three SimpleNamespace _note stand-ins that
only feed a single function stay local.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-21 11:03:48 -04:00
co-authored by Claude Fable 5
parent dad56a51bd
commit bbee0d0db1
38 changed files with 316 additions and 609 deletions
+8 -14
View File
@@ -9,6 +9,7 @@ from scribe.services.dedup import (
find_duplicate_note,
find_duplicate_rule,
)
from tests.helpers import fake_note
def _session_returning(note):
@@ -22,15 +23,9 @@ def _session_returning(note):
return s
def _fake_note(id=1, title="T", note_type="note"):
n = MagicMock()
n.id, n.title, n.note_type = id, title, note_type
return n
@pytest.mark.asyncio
async def test_title_exact_match_returns_title_duplicate():
note = _fake_note(id=10, title="Setup CI")
note = fake_note(id=10, title="Setup CI")
with patch("scribe.services.dedup.async_session",
return_value=_session_returning(note)):
# whitespace/case differences are normalized away
@@ -54,7 +49,7 @@ async def test_short_body_skips_semantic_check():
@pytest.mark.asyncio
async def test_semantic_match_when_body_substantial():
hit = _fake_note(id=20, title="Existing", note_type="note")
hit = fake_note(id=20, title="Existing", note_type="note")
sem = AsyncMock(return_value=[(0.93, hit)])
with patch("scribe.services.dedup.async_session",
return_value=_session_returning(None)), \
@@ -82,7 +77,7 @@ async def test_gate_catches_a_duplicate_hiding_in_a_later_chunk():
n_chunks = len(chunk_document("Title", body))
assert n_chunks > 1, "test body must actually chunk"
hit = _fake_note(id=30, title="The existing decision", note_type="note")
hit = fake_note(id=30, title="The existing decision", note_type="note")
# Every chunk misses except the LAST one the gate will ask about.
sem = AsyncMock(side_effect=[[] for _ in range(n_chunks - 1)] + [[(0.94, hit)]])
with patch("scribe.services.dedup.async_session",
@@ -97,7 +92,7 @@ async def test_gate_catches_a_duplicate_hiding_in_a_later_chunk():
@pytest.mark.asyncio
async def test_semantic_match_of_other_note_type_is_ignored():
other = _fake_note(id=21, title="X", note_type="process")
other = fake_note(id=21, title="X", note_type="process")
sem = AsyncMock(return_value=[(0.97, other)])
with patch("scribe.services.dedup.async_session",
return_value=_session_returning(None)), \
@@ -108,7 +103,7 @@ async def test_semantic_match_of_other_note_type_is_ignored():
@pytest.mark.asyncio
async def test_rule_title_match_in_topic():
rule = _fake_note(id=47, title="Honor the multi-user sharing ACL")
rule = fake_note(id=47, title="Honor the multi-user sharing ACL")
with patch("scribe.services.dedup.async_session",
return_value=_session_returning(rule)):
dup = await find_duplicate_rule(
@@ -171,8 +166,7 @@ def _session_sequence(results):
async def test_same_location_is_a_duplicate_however_it_is_described():
"""The measured false NEGATIVE: identical code at an identical
repo·path·symbol was created because the prose around it differed."""
existing = _fake_note(id=30, title=".btn-primary — a page's main action",
note_type="snippet")
existing = fake_note(id=30, title=".btn-primary — a page's main action", note_type="snippet")
sem = AsyncMock()
with patch("scribe.services.dedup.async_session",
return_value=_session_sequence([None, existing])), \
@@ -193,7 +187,7 @@ async def test_same_location_is_a_duplicate_however_it_is_described():
@pytest.mark.asyncio
async def test_identical_code_is_a_duplicate_at_a_different_location():
existing = _fake_note(id=31, title="group_pairs", note_type="snippet")
existing = fake_note(id=31, title="group_pairs", note_type="snippet")
with patch("scribe.services.dedup.async_session",
return_value=_session_sequence([None, None, existing])), \
patch("scribe.services.dedup.embeddings_svc.semantic_search_notes",