Skip to content

Conversation

@AndreasTu
Copy link
Member

@AndreasTu AndreasTu commented Nov 1, 2025

The usage of

SpyStatic(Type){
}

had thrown an NullPointerException , because the closure got automatically converted into IMockMakerSettings.

This adds a meaningful error message for the user to use SpyStatic(Type) without a Closure instead of SpyStatic(Type){}.

@AndreasTu AndreasTu added this to the 2.4-M7 milestone Nov 1, 2025
@AndreasTu AndreasTu self-assigned this Nov 1, 2025
The usage of
SpyStatic(Type){}
had thrown an NullPointerException,
because the closure got automatically converted into IMockMakerSettings.
@codecov
Copy link

codecov bot commented Nov 1, 2025

Codecov Report

❌ Patch coverage is 91.66667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 82.07%. Comparing base (ac06a53) to head (f3747e6).

Files with missing lines Patch % Lines
...spockframework/mock/runtime/MockMakerRegistry.java 91.66% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #2254   +/-   ##
=========================================
  Coverage     82.07%   82.07%           
- Complexity     4753     4757    +4     
=========================================
  Files           465      465           
  Lines         14872    14882   +10     
  Branches       1877     1877           
=========================================
+ Hits          12206    12215    +9     
  Misses         1978     1978           
- Partials        688      689    +1     
Files with missing lines Coverage Δ
...e/src/main/java/spock/mock/IMockMakerSettings.java 100.00% <ø> (ø)
...spockframework/mock/runtime/MockMakerRegistry.java 97.24% <91.66%> (-0.74%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AndreasTu AndreasTu modified the milestones: 2.4-M7, 2.4 Nov 8, 2025
* Fix filter blocks with shared fields and derived data variables spockPull:2088[]
* Fix combined labels with comments being ignored spockPull:2121[]
* Fix boxed Boolean `is` getter methods not properly mocked in Groovy <= 3 spockIssue:2131[]
* Fix `SpyStatic()` with an interaction closure throws NullPointerException spockPull:2254[]
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this misleading? IMO, this adds a feature that didn't exist before.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes it does. I am not really convinced that a user should use the new syntax:

SpyStatic(Type){
  1 * Type.method() >> true
}

because it does not work so great, due to the Class instance issues, e.g. IDE support.

The better syntax is the documented one, without any closure.

SpyStatic(Type)
1 * Type.method() >> true

As I said, I can also remove the new syntax and add a second method to IMockMakerSettings to prevent the auto-conversion, if you like that better.

Copy link
Member Author

Choose a reason for hiding this comment

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

@leonard84 I have changed PR to not use new API, you can have a look what you like better :).

Copy link
Member Author

Choose a reason for hiding this comment

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

I changed it again, because the new method to IMockMakerSettings would break contribution API for external MockMakers.

Copy link
Member

Choose a reason for hiding this comment

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

And why do we not support something like

SpyStatic(Type) {
  1 * method() >> true
}

like we do for all other mock objects?
Imho it should be up to the user whether he does that or

SpyStatic(Type)
1 * Type.method() >> true

like is supported for all other mock objects.
And it should solve the problem, as with a Closure overload, that should be used.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I see.
But if you have that version readily available already, why do you think it could not make it in that variant into M7?
The changes are not super intrusive, are they?

Copy link
Member Author

Choose a reason for hiding this comment

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

Leonard sounded that he was not so convinced about that new API, especially the lack of IDE support.
So I made a non-API change bugfix.

Copy link
Member

@Vampire Vampire Nov 12, 2025

Choose a reason for hiding this comment

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

Just treat it like an instance is given in?
Yes, you then get also instance methods completed, but as you can also call static methods on instances, you also get the static methods.
On the other mock closures you also get both while calling the static does not really make sense.
So I'd say just add the @ClosureParams and @DelegatesTo annotations and add an ?: enclosingCall('SpyStatic') to the gdsl and whatever is necessary for the Eclipse-version and it should be fine enough?

Copy link
Member Author

Choose a reason for hiding this comment

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

Wouldn't you get IDE warnings that static methods are called on an instance?

Actually before this, I would perfer the nothing at all as in my commit and the user shall use the class syntax inside the closure, which works fine and completes correctly.

SpyStatic(Type){
  1 * Type.method() >> true
}

Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't you get IDE warnings that static methods are called on an instance?

I don't think the IDE can warn about this, because due to the duck-typing of Groovy, the IDE cannot know whether the instance might also have an instance method with that name at runtime. If it complains, I'd say that is an IDE bug.

But actually I do not see a warning even with

@DelegatesTo(strategy = Closure.DELEGATE_FIRST, genericTypeIndex = 0)
@ClosureParams(FirstParam.FirstGenericType.class)

But you can also do

@DelegatesTo(strategy = Closure.DELEGATE_FIRST)
@ClosureParams(FirstParam.class)

and then the type is correctly considered to be Class<StaticClass> and the static methods are completed as expected too.

And the ?: enclosingCall('StaticSpy') in the spock.gdsl should also work as expected, as it should also deliver Class<StaticClass> as type and thus be correct.

For the spock_tests.dsld I'd expect the same.

@AndreasTu AndreasTu requested a review from leonard84 November 8, 2025 19:06
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.

3 participants