Class JunitExtensionSupport
- java.lang.Object
-
- ru.vyarus.spock.jupiter.JunitExtensionSupport
-
- All Implemented Interfaces:
org.spockframework.runtime.extension.IGlobalExtension
public class JunitExtensionSupport extends java.lang.Object implements org.spockframework.runtime.extension.IGlobalExtensionGlobal extension applied to all specs. Searches for declared junit extensions and calls them simulating junit extensions lifecycle. Supported all the same declaration methods as with junit:@ExtendsWithdeclaration on class, method, field or parameter- Custom annotations on class, method, field or parameter
@RegisterExtensionon static or non-static fields- Parameters injection into fixture and test methods
ExecutionConditionson class or method (so, for example,Disabledwill force skipping tests.
Junit extensions are executed before spock extensions. For example,
BeforeAllCallbackextension would be executed before spock extensions usinginterceptSetupSpecMethod(because extension is global it would be executed before all other spock extensions and that's why junit extensions will work in priority).Supported almost all junit extension types, except
ExtensionUtils.UNSUPPORTED_EXTENSIONS(exception handling, test watching, invocation interceptor and of course test instance factory). If not supported extension type would be detected in extension, warning will be logged.Auto-detected (service loader declared extensions), default and synthetic junit extensions are not supported: auto-detection would be not obvious (such extensions could always be registered manually), and the other two are too jupiter specific.
Implementation copies and re-use many jupiter-engine mechanisms (junit-jupiter-engine artifact) and so works (mostly) exactly the same as in jupiter (5.8). There are comments all over the code for jupiter-engine reference implementations.
Overall workflow:
- for each spec extension registry (
ExtensionRegistryis always created, containing all found extensions. ClassContextcreated to represent spec-level context (it will be used as parameter for before/after all and instance post processor extensions)- Before feature method execution, extended
ExtensionRegistryis created MethodContextcreated for feature level (it will be used as parameter for all other extensions)- Note that fresh method context is created for each method execution: in case of data-driven methods, each iteration will have its own context (required because method extensions must be renewed for each execution)
- Pre destroy extension is called after cleanup (after cleanup methods and cleanup of spock extensions)
Spock's shared state is not used: don't mark
RegisterExtensionextensions with@Shared- they will always be null as spock manage them on different instance. Use static fields to declare spec-wide extensions (same as in jupiter).Special API added to allow SPOCK extensions accessing junit shared state (used by all extensions to store values):
getStore(SpecInfo, Namespace)andgetStore(IMethodInvocation, Namespace). This might be used by spock extension authors to access junit state values or to simply using junit state as there is no alternative feature in spock itself.- Since:
- 25.11.2021
- See Also:
for lifecycle details
-
-
Constructor Summary
Constructors Constructor Description JunitExtensionSupport()
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description static org.junit.jupiter.api.extension.ExtensionContext.StoregetStore(org.spockframework.runtime.extension.IMethodInvocation invocation, org.junit.jupiter.api.extension.ExtensionContext.Namespace namespace)In contrast togetStore(SpecInfo, Namespace)provide either class-level or method-level context (depends on test instance presence).static org.junit.jupiter.api.extension.ExtensionContext.StoregetStore(org.spockframework.runtime.model.SpecInfo spec, org.junit.jupiter.api.extension.ExtensionContext.Namespace namespace)Storage used by junit extensions to keep local state (see docs).voidvisitSpec(org.spockframework.runtime.model.SpecInfo spec)
-
-
-
Method Detail
-
visitSpec
public void visitSpec(org.spockframework.runtime.model.SpecInfo spec)
- Specified by:
visitSpecin interfaceorg.spockframework.runtime.extension.IGlobalExtension
-
getStore
public static org.junit.jupiter.api.extension.ExtensionContext.Store getStore(org.spockframework.runtime.model.SpecInfo spec, org.junit.jupiter.api.extension.ExtensionContext.Namespace namespace)Storage used by junit extensions to keep local state (see docs). Spock does not have anything like this. This method allows spock extension authors to access storage used by junit extensions and so access contained values. May be also used for storing values by spock extensions.Storage is hierarchical: there are spec level storage (used by
ConditionEvaluator,BeforeAllCallback,AfterAllCallbackandTestInstancePreDestroyCallbackwhen no test instance is available). For each test instance created for feature (test method or test method data-iteration) new storage created (seegetStore(IMethodInvocation, Namespace)for accessing). Child storage level could see all parent values, but not modify them.In short: this method provides class-wide (spec-wide) storage, which values are visible in all test methods. This is the same call as
ExtensionContext.getStore(Namespace). Method might be called at any time because extension is global and so will work before any other custom spock extension.- Parameters:
spec- specification instancenamespace- target namespace- Returns:
- namespaced storage instance
- Throws:
java.lang.NullPointerException- if junit extension interceptor could not be found
-
getStore
public static org.junit.jupiter.api.extension.ExtensionContext.Store getStore(org.spockframework.runtime.extension.IMethodInvocation invocation, org.junit.jupiter.api.extension.ExtensionContext.Namespace namespace)In contrast togetStore(SpecInfo, Namespace)provide either class-level or method-level context (depends on test instance presence). In most cases simply use this method to get storage from the most actual context level (but if you need only root level use spec-based method: for example, might be useful if you need to modify root storage values).Feature-wide storage context created on just after spock initialization event (not shared initialization!) and destroyed after cleanup event. New instance created for EACH test method execution (in case of data-driven tests for each iteration!).
Method level context is used for junit extensions:
BeforeEachCallback,BeforeTestExecutionCallback,AfterTestExecutionCallback,ParameterResolver,AfterEachCallbackandTestInstancePreDestroyCallback.This is the same call as
ExtensionContext.getStore(Namespace). Method context will see all values from spec-level, but will not be able to modify them (if you try to set value it would modify method level only; same for remove).- Parameters:
invocation- spock extension parameternamespace- target namespace- Returns:
- namespaced storage instance (method or class level)
- Throws:
java.lang.NullPointerException- if junit extension interception not found, test instance is not yet available or method context not found when should be
-
-