Skip to content

feat(bridge-rector): convert PHPUnit mocks onto the Double bridge - #333

Open
roxblnfk wants to merge 1 commit into
1.xfrom
feat/rector-mock-to-double
Open

feat(bridge-rector): convert PHPUnit mocks onto the Double bridge#333
roxblnfk wants to merge 1 commit into
1.xfrom
feat/rector-mock-to-double

Conversation

@roxblnfk

Copy link
Copy Markdown
Member

🔍 What was changed

  • Added CreateMockToDoubleRector (PHPUnit → Testo set): converts PHPUnit mocks/stubs onto the Double bridge (testo/bridge-double), which is the target API the old MockToTestoRector stub was written without.
    • $this->createMock(X) / $this->createStub(X)\JMac\Testing\Double::for(X).
    • configuration chain: the invocation matcher moves onto the verb (anyallows, everything else keeps expects and folds into times()/never()oncetimes(1), exactlytimes, atLeastOnce/atLeast/atMosttimes(minimum:/maximum:)), the method name moves off ->method('m') onto expects('m')/allows('m'), and returns map willReturn/willReturnOnConsecutiveCallsreturns, willThrowExceptionthrows, willReturnCallbackresolves (plus the legacy will($this->returnValue()/throwException()/returnCallback()) wrappers).
  • Narrowed the MockToTestoRector stub, FEATURE_PARITY.md, TODO.md and the migrate-from-phpunit skill to the residual manual forms (getMockBuilder, prophesize, willReturnMap/willReturnSelf/willReturnArgument, variable matcher, with() constraint objects).

How it works

  • Two node types: the chain rebuild runs at statement level (Expression), the createMock/createStub rewrite at call level (MethodCall).
  • All-or-nothing per chain: a chain carrying an unmappable link is left whole, so the inner expects()->method() is never rewritten on its own.
  • Idempotent: a converted chain (expects('m') with a string argument, Double return verbs) does not re-trigger on a later pass.

Why?

The Double bridge gave mocks a faithful Testo target for the first time, so the mock row moves from ⛔ to a documented 🟡. Argument constraints inside with() are passed through untouched — a literal expected value converts cleanly, a constraint object does not and stays manual.

Review notes

Rector 2 exposes no parent-node attribute to rules (AttributeKey::PARENT_NODE is gone), so "am I the outermost call of the chain?" can't be asked at call level — a call-level rebuild converts the inner sub-chain of an otherwise-unconvertible statement. Anchoring the rebuild on the Expression statement instead is what makes the conversion all-or-nothing.

Checklist

  • How was this tested:
    • Unit tests added
  • 9 fixtures cover factory, every matcher, stub-style method(), legacy will(), inline factory+chain, and two left-unchanged cases (unsupported link, non-mock chain). Full Rector bridge suite green (204 tests).

CreateMockToDoubleRector turns createMock/createStub and their expects()/method()/will*() chains into \JMac\Testing\Double calls, now that testo/bridge-double supplies the target API the stub rule was written without. The invocation matcher moves onto the verb (any→allows, else expects + times()/never()), the method name onto expects('m')/allows('m'), and the return verbs onto returns/throws/resolves.

The chain is rebuilt at statement level, not per call: an unmappable link (willReturnMap, willReturnSelf, a variable matcher, with() constraint objects, getMockBuilder, prophesize) leaves the whole statement untouched instead of the inner expects()->method() being rewritten on its own. The MockToTestoRector stub, FEATURE_PARITY.md, TODO.md and the migrate-from-phpunit skill are narrowed to those residual manual forms.

Assisted-By: Claude Opus 4.8 <noreply@anthropic.com>
@roxblnfk
roxblnfk requested a review from a team as a code owner September 11, 2026 19:53
@codecov

codecov Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 87 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...or/src/PhpunitToTesto/CreateMockToDoubleRector.php 0.00% 84 Missing ⚠️
...ge/rector/src/PhpunitToTesto/MockToTestoRector.php 0.00% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant