Skip to content

Allow declaring mock interactions outside a Specification via MockInteractionSupport#2375

Draft
leonard84 wants to merge 1 commit into
masterfrom
external-mock-interactions-1-mock-interaction-support
Draft

Allow declaring mock interactions outside a Specification via MockInteractionSupport#2375
leonard84 wants to merge 1 commit into
masterfrom
external-mock-interactions-1-mock-interaction-support

Conversation

@leonard84

Copy link
Copy Markdown
Member

Introduce the compiler SPI for routing mock interactions (and mock creation)
through an owning Specification located outside the spec, plus the first
mechanism that uses it: the MockInteractionSupport interface.

A class implementing spock.mock.MockInteractionSupport supplies the owning
spec through getSpecification(); its methods may then declare interactions
and create mocks exactly as inside a spec. SpockTransform rewrites each
declared method in place, routing creation/interactions through
getSpecification(). A class cannot be both a Specification and a
MockInteractionSupport. Rewritten methods are guarded with Checks.notNull
so a missing (unattached) spec fails fast with a clear error.

Foundation included here:

  • Spec-locator seam: IRewriteResources.getSpecificationReference() and
    SpecialMethodCall.expand(Expression), consumed by DeepBlockRewriter,
    SpecRewriter, and DefaultConditionRewriterResources.
  • MockingApi converted from a class to an interface (with default methods) so
    non-spec types can mix in the factory methods; Specification implements MockingApi; ClosureParameterTypeFromVariableType accepts interface
    implementors.
  • External-rewriter infra: ExternalRewriteResources, ExternalInteractionRewriter,
    ExternalInteractionMethod, and the Checks.notNull(T, String) overload.

Tests cover the seam, the MockingApi interface conversion, the closure-param
path, the external rewrite resources, and MockInteractionSupport behaviour
(cardinality, stubbing, mock creation, null-spec guard, static-scope error,
both-spec-and-support error), plus an AST snapshot of the rewritten output.

…eractionSupport

Introduce the compiler SPI for routing mock interactions (and mock creation)
through an owning Specification located outside the spec, plus the first
mechanism that uses it: the `MockInteractionSupport` interface.

A class implementing `spock.mock.MockInteractionSupport` supplies the owning
spec through `getSpecification()`; its methods may then declare interactions
and create mocks exactly as inside a spec. `SpockTransform` rewrites each
declared method in place, routing creation/interactions through
`getSpecification()`. A class cannot be both a `Specification` and a
`MockInteractionSupport`. Rewritten methods are guarded with `Checks.notNull`
so a missing (unattached) spec fails fast with a clear error.

Foundation included here:
- Spec-locator seam: `IRewriteResources.getSpecificationReference()` and
  `SpecialMethodCall.expand(Expression)`, consumed by `DeepBlockRewriter`,
  `SpecRewriter`, and `DefaultConditionRewriterResources`.
- `MockingApi` converted from a class to an interface (with default methods) so
  non-spec types can mix in the factory methods; `Specification implements
  MockingApi`; `ClosureParameterTypeFromVariableType` accepts interface
  implementors.
- External-rewriter infra: `ExternalRewriteResources`, `ExternalInteractionRewriter`,
  `ExternalInteractionMethod`, and the `Checks.notNull(T, String)` overload.

Tests cover the seam, the MockingApi interface conversion, the closure-param
path, the external rewrite resources, and MockInteractionSupport behaviour
(cardinality, stubbing, mock creation, null-spec guard, static-scope error,
both-spec-and-support error), plus an AST snapshot of the rewritten output.
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4567ed1f-adca-4bba-8a89-e6795c1907a1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Jun 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.44068% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.42%. Comparing base (b2699ee) to head (4ebfc49).

Files with missing lines Patch % Lines
...ramework/compiler/ExternalInteractionRewriter.java 90.24% 2 Missing and 2 partials ⚠️
...ckframework/compiler/ExternalRewriteResources.java 76.47% 4 Missing ⚠️
...ork/mock/ClosureParameterTypeFromVariableType.java 63.63% 2 Missing and 2 partials ⚠️
...c/main/java/spock/mock/MockInteractionSupport.java 0.00% 3 Missing ⚠️
...va/org/spockframework/compiler/SpockTransform.java 95.83% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #2375      +/-   ##
============================================
+ Coverage     82.33%   82.42%   +0.08%     
- Complexity     4877     4910      +33     
============================================
  Files           474      478       +4     
  Lines         15205    15314     +109     
  Branches       1935     1954      +19     
============================================
+ Hits          12519    12622     +103     
  Misses         1993     1993              
- Partials        693      699       +6     
Files with missing lines Coverage Δ
...java/org/spockframework/compiler/AstNodeCache.java 100.00% <100.00%> (ø)
...org/spockframework/compiler/DeepBlockRewriter.java 98.22% <100.00%> (ø)
...g/spockframework/compiler/NoSpecialMethodCall.java 52.17% <ø> (ø)
...java/org/spockframework/compiler/SpecRewriter.java 93.93% <100.00%> (-0.25%) ⬇️
...org/spockframework/compiler/SpecialMethodCall.java 93.85% <100.00%> (+0.05%) ⬆️
...r/condition/DefaultConditionRewriterResources.java 93.75% <100.00%> (+0.41%) ⬆️
...work/compiler/model/ExternalInteractionMethod.java 100.00% <100.00%> (ø)
.../src/main/java/org/spockframework/util/Checks.java 70.58% <100.00%> (+6.30%) ⬆️
...k-core/src/main/java/spock/lang/Specification.java 79.16% <100.00%> (ø)
...pock-core/src/main/java/spock/mock/MockingApi.java 93.54% <ø> (-0.11%) ⬇️
... and 5 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@testlens-app

testlens-app Bot commented Jun 13, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: 4ebfc49
▶️ Tests: 99431 executed
⚪️ Checks: 61/61 completed


Learn more about TestLens at testlens.app.

Comment on lines +59 to +63
this.specificationReferenceFactory = specificationReferenceFactory;
this.currentMethod = currentMethod;
this.nodeCache = nodeCache;
this.sourceLookup = sourceLookup;
this.errorReporter = errorReporter;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null checks would be nice.

@Override
public VariableExpression captureOldValue(Expression oldValue) {
throw new UnsupportedOperationException("old() is not supported outside a then-block");
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the UnsupportedOpExceptions, maybe we should split the interface IRewriteResources into two parts to better fit the use case.

@@ -0,0 +1,21 @@
package org.spockframework.mock

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copyright

A class cannot be both a `Specification` and a `MockInteractionSupport`, because a spec already has the full capability.

If you forget to attach the fixture, using it fails fast with a clear error that tells you the spec is missing.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May write something like: An MockInteractionSupport instance should not be shared over multiple Specification, if parallel execution is enabled, because this will lead to flaky test execution.

Comment on lines +62 to +65
this.nodeCache = nodeCache;
this.errorReporter = errorReporter;
this.sourceLookup = sourceLookup;
this.allowCreation = allowCreation;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May some nullchecks.

* <p>A class that is both a {@code Specification} and implements this interface
* is a compile error: the spec already has the full capability.
*
* @since 2.5

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also write something about parallel execution and the same instance, similar to the comment in the docs.

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.

2 participants