{"id":22707579,"url":"https://github.com/xvik/spock-junit5","last_synced_at":"2026-02-06T13:21:09.384Z","repository":{"id":38110068,"uuid":"431628436","full_name":"xvik/spock-junit5","owner":"xvik","description":"Junit 5 extensions support for Spock Framework 2","archived":false,"fork":false,"pushed_at":"2026-02-02T12:04:13.000Z","size":460,"stargazers_count":10,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-03T01:35:00.472Z","etag":null,"topics":["junit5","spock-framework"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xvik.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-11-24T21:07:43.000Z","updated_at":"2026-02-02T12:04:18.000Z","dependencies_parsed_at":"2023-12-14T06:27:35.423Z","dependency_job_id":"3514907a-0318-4cb4-b8bd-f7246ae46d6c","html_url":"https://github.com/xvik/spock-junit5","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/xvik/spock-junit5","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvik%2Fspock-junit5","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvik%2Fspock-junit5/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvik%2Fspock-junit5/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvik%2Fspock-junit5/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xvik","download_url":"https://codeload.github.com/xvik/spock-junit5/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvik%2Fspock-junit5/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29162156,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-06T12:44:37.655Z","status":"ssl_error","status_checked_at":"2026-02-06T12:44:13.991Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["junit5","spock-framework"],"created_at":"2024-12-10T10:13:28.654Z","updated_at":"2026-02-06T13:21:09.368Z","avatar_url":"https://github.com/xvik.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# spock-junit5\n\n[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](http://www.opensource.org/licenses/MIT)\n[![CI](https://github.com/xvik/spock-junit5/actions/workflows/CI.yml/badge.svg)](https://github.com/xvik/spock-junit5/actions/workflows/CI.yml)\n[![Appveyor build status](https://ci.appveyor.com/api/projects/status/github/xvik/spock-junit5?svg=true)](https://ci.appveyor.com/project/xvik/spock-junit5)\n[![codecov](https://codecov.io/gh/xvik/spock-junit5/branch/master/graph/badge.svg)](https://codecov.io/gh/xvik/spock-junit5)\n\n**Pay attention**: artifacts differ for junit 5 and junit 6 (see [compatibility](#compatibility) section):\n\n* `spock-junit6` for junit 6\n* `spock-junit5` for junit 5\n\nVersion is not reset for spock-junit6 to avoid usage mistakes.   \nAlso, different artifact names should avoid dependabot \"spam\" for older versions\n\n`spock-junit5` is in the [separate branch](https://github.com/xvik/spock-junit5/tree/junit5)\n\n### About\n\nJunit 5 and 6 (jupiter) [extensions](https://junit.org/junit5/docs/current/user-guide/#extensions) support\nfor [Spock Framework](https://spockframework.org/) 2: allows using junit 5 (6) extension in spock (like it was with\njunit 4 rules in spock 1).\n\nFeatures:\n\n* Supports almost all junit extension types. Problem may appear only with extensions requiring `TestInstanceFactory`\n  which is impossible to support because spock manage test instance itself.\n    - Warning message would indicate not supported extension types (if usage detected)\n* Supports all the same registration types:\n    - @ExtendWith on class, method, field or param\n    - Custom annotations on class, method, field or param\n    - @RegisterExtension on static and usual fields (direct registration)\n* Supports parameters injection in test and fixture methods (but not in constructor)\n* Support junit `ExecutionConditions` (for example, junit `@Disabled` would work)\n* Implicit activation: implemented as global spock extension\n* API for spock extensions to use junit value storage\n  (to access values stored by junit extensions or for direct usage because spock does not provide such feature)\n\nExtensions behaviour is the same as in jupiter engine (the same code used where possible). Behavior in both engines\nvalidated with tests.\n\n#### Motivation\n\nOriginally developed for [dropwizard-guicey](https://github.com/xvik/dropwizard-guicey) to avoid maintaining special\nspock extensions.\n\nSpock 1 provides spock-junit4 module to support junit 4 rules. At that time spock extensions model was \"light years\"\nahead\nof junit. But junit 5 extensions are nearly equal in power to spock extensions (both has pros and cons). It is a big\nloss for spock to ignore junit5 extensions:\njunit extensions are easier to write, but spock is still much better for writing tests.\n\nModule named `spock-junit5` by analogy with legacy `spock-junit4` module.\nThere should be no official `spock-junit5` module so name would stay unique\n(there are discussions about official `spock-jupiter` module with value storage implementation).\n\n[More details about motivation and realization in the blog post](https://blog.vyarus.ru/using-junit-5-extensions-in-spock-2-tests).\n\n### Setup\n\n[![Maven Central](https://img.shields.io/maven-central/v/ru.vyarus/spock-junit6.svg?style=flat)](https://central.sonatype.com/artifact/ru.vyarus/spock-junit6)\n\nMaven:\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003eru.vyarus\u003c/groupId\u003e\n    \u003cartifactId\u003espock-junit6\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nGradle:\n\n```groovy\nimplementation 'ru.vyarus:spock-junit6:2.0.1'\n```\n\n**For junit 5 setup** see [junit5 docs](https://github.com/xvik/spock-junit5/tree/junit5).\n\n### Compatibility\n\n`spock-junit6` compiled for java 17 (junit6 requires java 17), junit 6  \n`spock-junit5` compiled for java 8 (tested up to java 21), junit 5.14\n\nThe only transitive library dependency is *junit-jupiter-api*: to bring in required junit annotations\nand to prevent usage with lower junit versions.\n\nThere is a high chance that a more recent module version will work with older junit versions\n(it depends on what extensions are used).\nIn case of problems (like `NoClassDefFoundError`) select a lower module version (according to your junit version)\n\n| Junit       | Artifact                | Version                                                  | Junit API Changes                                            \n|-------------|-------------------------|----------------------------------------------------------|--------------------------------------------------------------\n| 6.0         | **spock\u0026#x2011;junit6** | [2.0.1](https://github.com/xvik/spock-junit5/tree/2.0.1) | value storage API changes, java 17 required                              \n| 5.12 - 5.14 | spock\u0026#x2011;junit5     | [1.4.1](https://github.com/xvik/spock-junit5/tree/1.4.1) | new methods in ExtensionContext                              \n| 5.11        | spock\u0026#x2011;junit5     | [1.3.0](https://github.com/xvik/spock-junit5/tree/1.3.0) | changed initialization order for non-static extension fields \n| 5.9 - 5.10  | spock\u0026#x2011;junit5     | [1.2.0](https://github.com/xvik/spock-junit5/tree/1.2.0) |\n| 5.7 - 5.8   | spock\u0026#x2011;junit5     | [1.0.1](https://github.com/xvik/spock-junit5/tree/1.0.1) |\n\n##### Snapshots\n\nYou can use snapshot versions through [JitPack](https://jitpack.io):\n\n* Go to [JitPack project page](https://jitpack.io/#xvik/spock-junit5)\n* Select `Commits` section and click `Get it` on commit you want to use (top one - the most recent)\n* Follow displayed instruction: add repository and change dependency (NOTE: due to JitPack convention artifact group\n  will be different)\n\n### Usage\n\nJunit 5 extensions could be\napplied [as usual](https://junit.org/junit5/docs/current/user-guide/#extensions-registration):\n\n```groovy\n@ExtendWith([Ext0, Ext1])\nclass Test extends Specification {\n\n    @ExtendWith(Ext2)\n    static Integer field1\n\n    @ExtendWith(Ext3)\n    Integer field2\n\n    void setupSpec(@ExtendWith(Ext4) Integer arg) {\n        // ...\n    }\n\n    // same for setup method    \n\n    @ExtendWith(Ext5)\n    def \"Sample test\"(@ExtendWith(Ext6) Integer arg) {\n        // ...\n    }\n}\n```\n\nAll these `@ExtendWith` would be found and registered.\n\n#### Custom annotations\n\nSame as in junit, custom annotations could be used instead of direct `@ExtendWith`:\n\n```groovy\n@Target([ElementType.TYPE, ElementType.METHOD])\n@Retention(RetentionPolicy.RUNTIME)\n@ExtendWith([Ext0, Ext1])\n@interface MyExt {}\n\n@MyExt\nclass Test extends Specification {\n    // ...\n}\n```\n\n#### Programmatic registration\n\n[Programmatic registration](https://junit.org/junit5/docs/current/user-guide/#extensions-registration-programmatic) is\nalso te same:\n\n```groovy\nclass Test extends Specification {\n\n    @RegisterExtension\n    static Ext1 ext = new Ext1()\n\n    @RegisterExtension\n    Ext2 ext2 = new Ext2()\n}\n```\n\nNOTE: `@Shared` spock fields are not supported\n\n#### Method parameters\n\nAs in junit, [`ParameterResolver`](https://junit.org/junit5/docs/current/user-guide/#writing-tests-dependency-injection)\nextensions could inject parameters into fixture and test method arguments (constructor is not supported because spock\ndoes not allow constructors usage):\n\n```groovy\n@ExtendWith(ParameterExtension)\nclass Test extends Specification {\n\n    void setupSpec(Integer arg) { ... }\n\n    void cleanupSpec(Integer arg) { ... }\n\n    void setup(Integer arg) { ... }\n\n    void cleanup(Integer arg) { ... }\n\n    def \"Sample test\"(Integer arg) { ... }\n}\n```\n\nIf extension implemented like this:\n\n```java\npublic class ParameterExtension implements ParameterResolver {\n\n    @Override\n    public boolean supportsParameter(ParameterContext parameterContext,\n                                     ExtensionContext extensionContext) throws ParameterResolutionException {\n        return parameterContext.getParameter().getType().equals(Integer.class);\n    }\n\n    @Override\n    public Object resolveParameter(ParameterContext parameterContext,\n                                   ExtensionContext extensionContext) throws ParameterResolutionException {\n        return 11;\n    }\n}\n```\n\nIn all spock methods argument would be set to 11.\n\nParameter resolution would be executed only on arguments marked as `MethodInfo.MISSING_ARGUMENT`,\nso [data-iteration usage](https://spockframework.org/spock/docs/2.0/data_driven_testing.html#data-tables)\nwould not be a problem:\n\n```groovy\nclass Test extends Specification {\n\n    @ExtendWith(ParameterExtension.class)\n    def \"Sample test\"(int a, Integer arg) {\n\n        when:\n        printn(\"iteration arg $a, junit arg $arg\");\n\n        then:\n        true\n\n        where:\n        a | _\n        1 | _\n        2 | _\n    }\n}\n```\n\nHere only `arg` parameter would be resolved with junit extension.\n\nNOTE: if junit extension will not be able to resolve parameter - it will remain as `MethodInfo.MISSING_ARGUMENT`\nand subsequent spock extension could insert correct value (junit extensions not own arguments processing).\n\n#### What is supported\n\nSupported:\n\n* ExecutionCondition\n* BeforeAllCallback\n* AfterAllCallback\n* BeforeEachCallback\n* AfterEachCallback\n* BeforeTestExecutionCallback\n* AfterTestExecutionCallback\n* ParameterResolver\n* TestInstancePostProcessor\n* TestInstancePreDestroyCallback\n* TestExecutionExceptionHandler\n* LifecycleMethodExecutionExceptionHandler\n\nNot supported:\n\n* TestTemplateInvocationContextProvider - junit specific feature (no need for support)\n* ClassTemplateInvocationContextProvider\n* BeforeClassTemplateInvocationCallback\n* AfterClassTemplateInvocationCallback\n* TestInstanceFactory - impossible to support because spock does not delegate test instance creation\n* TestInstancePreConstructCallback - impossible to support because spock does not delegate test instance creation\n* InvocationInterceptor - could be supported, but it is very specific\n* PreInterruptCallback - triggered by @Timeout extensions which is not supported (requires InvocationInterceptor)\n* TestWatcher - no need in context of spock\n\nOf course, constructor parameters injection is not supported because spock does not allow spec constructors.\n\n**What does \"extension not supported\" mean?**  \nIf extension implements not supported extension interface, like `TestWatcher`,\nthen methods for this interface would not be called on extension. That's all.  \nSuch interfaces might be used in extension for some \"additional features\" like logging and\nso extension would work perfectly in spock.\n\n##### Default junit extensions\n\nJunit register some extensions by default:\n\n```java\n    private static final List\u003cExtension\u003e DEFAULT_STATELESS_EXTENSIONS = Collections.unmodifiableList(Arrays.asList(//\n        new DisabledCondition(),\n        new AutoCloseExtension(),\n        new TimeoutExtension(),\n        new RepeatedTestExtension(),\n        new TestInfoParameterResolver(),\n        new TestReporterParameterResolver()));\n```\n\nPlus, junit loads extensions from `META-INF/services/org.junit.jupiter.api.extension.Extension` file.\n\n**None of this would work in context of spock**.   \nThis is intentional: as not all extensions are supported, then automatic loading may\ncause unexpected behavior. If you need any default extension - register it manually.\n\nAnnotation-based extensions like `@Disabled` or `@AutoClose` would work in spock because they are declared with\nannotations.\nExtensions like `TestInfoParameterResolver` could be easully enabled with `@ExtendWith(TestInfoParameterResolver.class)`\n\nSo overall not automatic defaults should not be a problem.\n\n### Usage with Spring-Boot\n\nOnly spock and spock-junit5 dependencies would be required:\n\n**Spring-boot 4**:\n\n```groovy\ntestImplementation 'org.spockframework:spock-core:2.4-groovy-5.0'\ntestImplementation 'ru.vyarus:spock-junit6:2.0.1'\n```\n\n**Spring-boot 3**:\n\n```groovy\ntestImplementation 'org.spockframework:spock-core:2.4-groovy-4.0'\ntestImplementation 'ru.vyarus:spock-junit5:1.4.1'\n```\n\nNote that [spock-spring module](https://spockframework.org/spock/docs/2.3/modules.html#_spring_module)\n**should not be used** together with spock-junit5 for spring-boot tests!  \nSpock-junit5 would activate native spring junit5 extensions **the same way** as in raw junit\n\nExample MVC test (based\non [this example](https://github.com/mkyong/spring-boot/blob/master/spring-boot-hello-world/src/test/java/com/mkyong/HelloControllerTests.java)):\n\n```groovy\n@SpringBootTest\n@AutoConfigureMockMvc\nclass ControllerTest extends Specification {\n\n    @Autowired\n    private MockMvc mvc\n\n    def \"Test welcome ok\"() {\n\n        mvc.perform(MockMvcRequestBuilders.get(\"/\").accept(MediaType.APPLICATION_JSON))\n                .andExpect(status().isOk())\n                .andExpect(content().string(equalTo(\"Hello World, Spring Boot!\")))\n\n        expect:\n        // ofc. it's a bad spock test, but just to show that extensions work the same way\n        true\n    }\n}\n```\n\nExample JPA test (based\non [this example](https://github.com/mkyong/spring-boot/blob/master/spring-data-jpa/src/test/java/com/mkyong/BookRepositoryTest.java)):\n\n```groovy\n@DataJpaTest\nclass BootTest extends Specification {\n\n    @Autowired\n    TestEntityManager testEM\n    @Autowired\n    BookRepository bookRepository\n\n    void setup() {\n        bookRepository.deleteAll()\n        bookRepository.flush()\n        testEM.clear()\n    }\n\n    def \"Test save\"() {\n\n        when:\n        Book b1 = new Book(\"Book A\", BigDecimal.valueOf(9.99), LocalDate.of(2023, 8, 31))\n        bookRepository.save(b1)\n        Long savedBookID = b1.getId()\n        Book book = bookRepository.findById(savedBookID).orElseThrow()\n\n        then:\n        savedBookID == book.getId()\n        \"Book A\" == book.getTitle()\n        BigDecimal.valueOf(9.99) == book.getPrice()\n        LocalDate.of(2023, 8, 31) == book.getPublishDate()\n    }\n}\n```\n\n### Spock @Shared state\n\n**Junit extensions would not be able to initialize `@Shared` fields**. So just don't use `@Shared`\non fields that must be initialized by junit extensions.\n\nThe reason is: shared fields are managed on a special test instance, different\nfrom instance used for test execution. But in junit lifecycle beforeEach\ncould be called only once (otherwise extensions may work incorrectly)\nand so it is called only with actual test instance.\n\nEven if junit extension initialize `@Shared` field - it would make no effect because\nit would be done on test instance instead of shared test instance and\non field access spock will return shared instance field value (not initialized - most likely, null).\n\nThis limitation should not be a problem.\n\n### Lifecycle\n\nJunit extensions support is implemented as global spock extension and so it would be executed before any other\nannotation-driven spock extension.\n\nThe following code shows all possible fixture methods and all possible interceptors\navailable for extension (from [spock docs](https://spockframework.org/spock/docs/2.0/extensions.html#_interceptors))\n\n```groovy\n@ExtendWith(JunitExtension)\n@SpockExtension\nclass SpockLifecyclesOrder extends Specification {\n\n    // fixture methods\n\n    void setupSpec() { ... }\n\n    void cleanupSpec() { ... }\n\n    void setup() { ... }\n\n    void cleanup() { ... }\n\n    // feature\n\n    def \"Sample test\"() { ... }\n}\n\n@Retention(RetentionPolicy.RUNTIME)\n@Target([ElementType.TYPE, ElementType.METHOD, ElementType.FIELD])\n@ExtensionAnnotation(SpockExtensionImpl)\n@interface SpockExtension {\n    String value() default \"\";\n}\n\nclass SpockExtensionImpl implements IAnnotationDrivenExtension\u003cSpockExtension\u003e {\n    @Override\n    void visitSpecAnnotation(SpockExtension annotation, SpecInfo spec) {\n        spec.addSharedInitializerInterceptor new I('shared initializer')\n        spec.sharedInitializerMethod?.addInterceptor new I('shared initializer method')\n        spec.addInterceptor new I('specification')\n        spec.addSetupSpecInterceptor new I('setup spec')\n        spec.setupSpecMethods*.addInterceptor new I('setup spec method')\n        spec.allFeatures*.addInterceptor new I('feature')\n        spec.addInitializerInterceptor new I('initializer')\n        spec.initializerMethod?.addInterceptor new I('initializer method')\n        spec.allFeatures*.addIterationInterceptor new I('iteration')\n        spec.addSetupInterceptor new I('setup')\n        spec.setupMethods*.addInterceptor new I('setup method')\n        spec.allFeatures*.featureMethod*.addInterceptor new I('feature method')\n        spec.addCleanupInterceptor new I('cleanup')\n        spec.cleanupMethods*.addInterceptor new I('cleanup method')\n        spec.addCleanupSpecInterceptor new I('cleanup spec')\n        spec.cleanupSpecMethods*.addInterceptor new I('cleanup spec method')\n        spec.allFixtureMethods*.addInterceptor new I('fixture method')\n    }\n\n    static class I implements IMethodInterceptor {\n        ...\n    }\n}\n```\n\n| Junit (context type)               | Spock                      | Kind                | Registration                                    |\n|------------------------------------|----------------------------|---------------------|-------------------------------------------------|\n|                                    | annotation extensions init |                     | IAnnotationDrivenExtension (all methods)        |\n|                                    | shared initializer         | SHARED_INITIALIZER  | spec.addSharedInitializerInterceptor            | \n|                                    | specification              | SPEC_EXECUTION      | spec.addInterceptor                             |\n| BeforeAllCallback (c)              |                            |                     |                                                 |\n|                                    | setup spec                 | SETUP_SPEC          | spec.addSetupSpecInterceptor                    |\n|                                    | setup spec method          | SETUP_SPEC          | spec.setupSpecMethods*.addInterceptor           |\n|                                    | fixture method             | SETUP_SPEC          | spec.allFixtureMethods*.addInterceptor          |\n|                                    | **TEST setupSpec**         |                     |                                                 |\n|                                    | initializer                | INITIALIZER         | spec.addInitializerInterceptor                  |\n| TestInstancePostProcessor (c)      |                            |                     |                                                 |\n|                                    | feature                    | FEATURE_EXECUTION*  | spec.allFeatures*.addInterceptor                |\n|                                    | iteration                  | ITERATION_EXECUTION | spec.allFeatures*.addIterationInterceptor       |\n| BeforeEachCallback (m)             |                            |                     |                                                 |\n|                                    | setup                      | SETUP               | spec.addSetupInterceptor                        |\n|                                    | setup method               | SETUP               | spec.setupMethods*.addInterceptor               |\n|                                    | fixture method             | SETUP               | spec.allFixtureMethods*.addInterceptor          | \n|                                    | **TEST setup**             |                     |                                                 |\n| BeforeTestExecutionCallback (m)    |                            |                     |                                                 |\n|                                    | feature method             | FEATURE             | spec.allFeatures*.featureMethod*.addInterceptor |\n|                                    | **TEST body**              |                     |                                                 |\n| AfterTestExecutionCallback (m)     |                            |                     |                                                 |\n|                                    | cleanup                    | CLEANUP             | spec.addCleanupInterceptor                      |\n|                                    | cleanup method             | CLEANUP             | spec.cleanupMethods*.addInterceptor             |\n|                                    | fixture method             | CLEANUP             | spec.allFixtureMethods*.addInterceptor          |\n|                                    | **TEST cleanup**           |                     |                                                 |\n| AfterEachCallback (m)              |                            |                     |                                                 |\n| TestInstancePreDestroyCallback (m) |                            |                     |                                                 |\n|                                    | cleanup spec               | CLEANUP_SPEC        | spec.addCleanupSpecInterceptor                  |\n|                                    | cleanup spec method        | CLEANUP_SPEC        | spec.cleanupSpecMethods*.addInterceptor         |\n|                                    | fixture method             | CLEANUP_SPEC        | spec.allFixtureMethods*.addInterceptor          \n|                                    | **TEST cleanupSpec**       |                     |                                                 |\n| AfterAllCallback (c)               |                            |                     |                                                 |\n\n\\* in spock 2.4 `FEATURE_EXECUTION` goes before `INITIALIZER`\n\nKind is a `IMethodInvocation.getMethod().getKind()`. It is shown in case if you use `AbstractMethodInterceptor` which\nuses kind for method dispatching.\n\nJunit extensions postfix means: (c) - class context, (m) - method context\n\n`ParameterResolver` not shown because it's called just before method execution.\n\n`ExecutionCondition` and `TestExecutionExceptionHandler` are also out of usual lifecycle.\n\n#### Contexts hierarchy\n\nLibrary use simplified junit contexts hierarchy:\n\n1. Global (engine) context\n2. Class context (created for each test class)\n3. Method context (created for each test method or data iteration)\n\nIn junit there are other possible contexts (for some specific features), but they are nto useful in context of spock.\n\nGlobal context created once for all tests. It might be used as a global data store:\n\n```java\n// BeforeAllCallback\npublic void beforeAll(ExtensionContext context) throws Exception {\n    // global storage (same for all tests)\n    Store store = context.getRoot().getStore(Namespace.create(\"ext\"));\n    if (store.get(\"some\") == null) {\n        // would be called only in first test with this extension \n        // (for other tests value would be preserved) \n        store.put(\"some\", \"val\");\n    }\n}\n```\n\nNOTE: this works exactly the same as it works in junit jupiter (showed just to confirm this ability).\n\n### Access storage from spock\n\nSpock extension could access junit value storage with:\n\n* `JunitExtensionSupport.getStore(SpecInfo, Namespace)` - obtain spec-level store\n* `JunitExtensionSupport.getStore(IMethodInvocation, Namespace)` - obtain method or spec level store (depends on hook)\n\nThe second method is universal - always providing the most actual context (method, if available):\n\n```groovy\nIMethodInterceptor interceptor = { invocation -\u003e\n    Store store = JunitExtensionSupport.getStore(invocation, ExtensionContext.Namespace.create('name'))\n}\n```\n\nThe problem may only appear if you'll need to modify value stored on class level (in this case use\n`JunitExtensionSupport.getStore(invocation.getSpec(), ExtensionContext.Namespace.create('name'))` to get class level\nstorage\n(common for all methods in test class)).\n\nComplete usage example:\n\n```groovy\n@Retention(RetentionPolicy.RUNTIME)\n@Target([ElementType.TYPE, ElementType.METHOD])\n@ExtensionAnnotation(StoreAwareExtension)\n@interface StoreAware {\n    String value() default \"\";\n}\n\nclass StoreAwareExtension implements IAnnotationDrivenExtension\u003cSpockStore\u003e {\n    @Override\n    void visitSpecAnnotation(SpockStore annotation, SpecInfo spec) {\n        ExtLifecycle ls = new ExtLifecycle()\n\n        // listening for setup spec phase and test method execution\n        spec.addSetupSpecInterceptor ls\n        spec.allFeatures*.featureMethod*.addInterceptor ls\n\n        // create store for extension values on class level\n        Store store = JunitExtensionSupport.getStore(spec, ExtensionContext.Namespace.create(StoreAwareExtension.name))\n        // and store annotation value there\n        store.put('val', annotation.value())\n    }\n}\n\nclass ExtLifecycle extends AbstractMethodInterceptor {\n\n    @Override\n    void interceptSetupSpecMethod(IMethodInvocation invocation) throws Throwable {\n        // access stored value\n        Object value = JunitExtensionSupport.getStore(invocation, ExtensionContext.Namespace.create(StoreAwareExtension.name)).get('val')\n        // do something\n    }\n\n    @Override\n    void interceptFeatureMethod(final IMethodInvocation invocation) throws Throwable {\n        // same store access here\n    }\n}\n```\n\n---\n[![java lib generator](http://img.shields.io/badge/Powered%20by-%20Java%20lib%20generator-green.svg?style=flat-square)](https://github.com/xvik/generator-lib-java)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxvik%2Fspock-junit5","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxvik%2Fspock-junit5","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxvik%2Fspock-junit5/lists"}