Issue when MockedStatic field is defined with an inline Mockito.mockStatic initialiser
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 74/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- java
- Ambito
- testing-qa
Direzione di ricerca
Inizia da org.openrewrite.java.testing.mockito.CloseUnclosedStaticMocks, in particolare dal percorso visitBlock() e dal relativo controllo dei metodi del ciclo di vita, usando il riproduttore inline con il campo MockedStatic riportato nell’issue. Aggiungi una copertura di regressione per questo caso nel corpo della classe e verifica che la recipe non generi più un’eccezione e preservi il campo quando la pulizia è già gestita, quindi esegui i test pertinenti di rewrite-testing-frameworks.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
What version of OpenRewrite are you using?
I am using
- Maven plugin:
org.openrewrite.maven:rewrite-maven-pluginv6.44.0 org.openrewrite.recipe:rewrite-springv6.35.0org.openrewrite.recipe:rewrite-testing-frameworksv3.42.0 (pulled in transitively by rewrite-spring)
The bug lives in org.openrewrite.java.testing.mockito.CloseUnclosedStaticMocks, in rewrite-testing-frameworks. It is reached transitively via:
org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5 → spring-boot-31.yml's org.openrewrite.java.testing.mockito.Mockito4to5Only → org.openrewrite.java.testing.mockito.Mockito1to4Migration → org.openrewrite.java.testing.mockito.CloseUnclosedStaticMocks (last recipe in Mockito1to4Migration's recipeList, per mockito.yml).
How are you running OpenRewrite?
I am using the Maven plugin (rewrite-maven-plugin:run), on a single-module project, running a declarative recipe chain that includes org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5.
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>6.44.0</version>
<configuration>
<activeRecipes>
<recipe>org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5</recipe>
</activeRecipes>
</configuration>
</plugin>
What is the smallest, simplest way to reproduce the problem?
package com.example;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
class MyTest {
private static final MockedStatic<CryptoUtil> MOCKED_CRYPTO_UTILS = Mockito.mockStatic(CryptoUtil.class);
}
Any test class that declares a MockedStatic field with an inline Mockito.mockStatic(...) initializer directly in the class body (as opposed to assigning it in a @BeforeAll/@BeforeEach lifecycle method) triggers the crash:
Root cause (confirmed by reading CloseUnclosedStaticMocks's source from rewrite-testing-frameworks-3.42.0-sources.jar): its visitBlock() override fires on any J.Block, but a class body is also represented as a J.Block in the LST, just like a method body. The recipe guards against lifecycle-method blocks (insideLifecycleMethod()), but not against the class-body block itself. So it mistakes this field declaration for an "unclosed local variable" inside a block, and attempts to wrap it in a try (#{any()}) {} template — which isn't valid for a field declaration (its modifiers, e.g. private static final, aren't compatible with a try-with-resources resource declaration). The resulting JavaTemplate.apply() call generates 2 statements instead of the expected 1 replacement statement, and throws.
Note that the recipe's separate assignment-based path (visitAssignment / DeclareMockVarAndClose, used when mockStatic() appears as VAR = Mockito.mockStatic(X.class); rather than as an inline field initializer) works correctly, including correctly recognizing a pre-existing manual .close() call as already handling cleanup. The bug is specific to the inline-field-initializer form.
What did you expect to see?
Since the field's MockedStatic is already closed manually elsewhere (e.g. in a matching @AfterAll), I'd expect the recipe to make no change, e.g.:
package com.example;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
class MyTest {
private static final MockedStatic<CryptoUtil> MOCKED_CRYPTO_UTILS = Mockito.mockStatic(CryptoUtil.class);
@AfterAll
static void afterAll() {
MOCKED_CRYPTO_UTILS.close();
}
}
What did you see instead?
At minimum, I'd expect the recipe to not crash the whole run — e.g. it could correctly detect the existing .close() call the way it already does for the assignment-based form, or leave inline-initialized class-body fields alone entirely if it can't safely rewrite them.
What is the full stack trace of any errors you encountered?
[ERROR] Failed to execute goal org.openrewrite.maven:rewrite-maven-plugin:6.44.0:run (default-cli) on project AppFunctionalTests: Execution default-cli of goal org.openrewrite.maven:rewrite-maven-plugin:6.44.0:run failed: Error while visiting app_name/AppFunctionalTests/filename.java: java.lang.IllegalArgumentException: Expected a template that would generate exactly one statement to replace one statement, but generated 2. Template:
[ERROR] try(__P__.<org.mockito.MockedStatic<Unknown>>/*__p0__*/p()) {}
[ERROR] Substitutions:
[ERROR] Substitutions(code=try(#{any()}) {}, genericTypes=[], parameters=[private static final MockedStatic<CryptoUtil> MOCKED_CRYPTO_UTILS = Mockito.mockStatic(CryptoUtil.class)], propertyPlaceholderHelper=org.openrewrite.internal.PropertyPlaceholderHelper@72eca5c5, typeVariables=[])
[ERROR] Statement:
[ERROR] private static final MockedStatic<CryptoUtil> MOCKED_CRYPTO_UTILS = Mockito.mockStatic(CryptoUtil.class)
at org.openrewrite.java.JavaTemplate.apply(JavaTemplate.java:...)
at org.openrewrite.java.testing.mockito.CloseUnclosedStaticMocks$CloseUnclosedStaticMocksVisitor.toTryWithResource(CloseUnclosedStaticMocks.java:...)
at org.openrewrite.java.testing.mockito.CloseUnclosedStaticMocks$CloseUnclosedStaticMocksVisitor.visitBlock(CloseUnclosedStaticMocks.java:...)
...
Are you interested in contributing a fix to OpenRewrite?
No.
- Lingua principale
- Java
- Stelle
- 100
- Fork
- 105
- Merge medio
- 2g 15h
- PR unite (30g)
- 13
Preparare l'ambiente
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di openrewrite/rewrite-testing-frameworks
-
bug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 68/100
openrewrite/rewrite-testing-frameworks#1126 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 70/100
openrewrite/rewrite-testing-frameworks#1125 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 65/100
openrewrite/rewrite-testing-frameworks#1124 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 3/5 1-2 giorni Idoneità per principianti 78/100
openrewrite/rewrite-testing-frameworks#1123 ·
I maintainer di solito rispondono entro 1 giorno
-
MigrateJUnitTestCase rewrites super.run(TestResult) to Assertions.run(...), which does not existAperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 68/100
openrewrite/rewrite-testing-frameworks#1114 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di openrewrite/rewrite-testing-frameworks
Issue simili
-
area/frontend good first issue kind/cooldown
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
beehive-lab/TornadoVM#1151 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
I maintainer di solito rispondono entro 1 giorno
-
(cbor) `maxStringLength` not consistently checked for chunked (indefinite-length) text valuesAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 77/100
FasterXML/jackson-dataformats-binary#823 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 90/100
I maintainer di solito rispondono entro 1 giorno