-
Notifications
You must be signed in to change notification settings - Fork 467
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable usage of Spring beans in @Shared fields, setupSpec() and cleanupSpec() #76
Comments
+1 We are doing this on a project, and as a workaround setting fields in the setup() method. However, some of those fields we want to use in 'where' blocks, so we have a dummy feature at the beginning to initialize the fields so that the next feature has them when the 'where' block is run. |
Could you give us a code example please? |
Here is what we currently do as workaround:
|
The following is a simplified version of what we are doing. My comment above refers to our "Dummy" feature below. If that feature isn't present, the @ContextConfiguration(
initializers = MyCustomApplicationContextInitializer.class,
classes = [ MyCustomTestConfig.class ]
)
@Stepwise
class SPCalendarSpec extends Specification {
@Shared
def static ResourceDTO createResourceDTO
@Shared
def static ResourceDTO updateResourceDTO
@Shared
def static String testUserId
@Autowired
public Environment environment
@Shared
def static String baseUrl
def setupSpec() {
/*
* Note: We cannot access Spring from this method, per this quote
* from the docs at https://code.google.com/p/spock/wiki/SpringExtension:
*
* "Note: Due to the way Spring's TestContext framework is designed,
* @Shared fields cannot currently be injected. This also means that
* setupSpec() and cleanupSpec() cannot get access to Spring beans."
*/
}
def setup() {
// Note: according to http://stackoverflow.com/questions/21149157/spock-all-shared-variables-are-null
// the 'where' block of each feature is run before this method, so any 'where' blocks
// using these variables get the values from the invokation of the previous feature.
baseUrl = buildLocalhostRootBaseURL();
testUserId = environment.getProperty("ob.user.testUserId")
createResourceDTO = new ResourceDTO()
createResourceDTO.setUserId(Integer.parseInt(testUserId))
createResourceDTO.setResourceName("CalendarName")
createResourceDTO.setSvcId(1)
updateResourceDTO = new ResourceDTO()
updateResourceDTO.setUserId(Integer.parseInt(testUserId))
updateResourceDTO.setResourceName("CalendarName2")
updateResourceDTO.setSvcId(1)
client = new RESTClient(baseUrl)
}
def RESTClient client
def String buildLocalhostRootBaseURL() {
return "http://" + environment.getProperty("tests.api.localhost") + ":" + environment.getProperty("tests.api.port") + environment.getProperty("tests.api.path") + "/"
}
// See comment at top of setup() method
def "Dummy test to call setup() and populate the variables from Spring"() { }
@Unroll
def "#method - Call #path using http should produce successful return code"() {
def response
when: "rest call"
if (method == "get" || method == "delete") {
response = client."${method}"(
path : path,
contentType : "application/json"
)
} else {
response = client."${method}"(
path : path,
contentType : "application/json",
body : body
)
}
then: "response 200/201"
response.status == successStatus
where:
method | body | path | successStatus
"put" | createResourceDTO | "resource" | 201
"get" | null | "resource/"+testUserId | 200
"post" | updateResourceDTO | "resource" | 200
"delete" | null | "resource/"+testUserId | 200
}
|
+1 for this feature. I have some Selenium tests that I'd like to convert to MockMvc tests, but I'm using |
+1 look forward for this feature |
According to @sbrannen (see sbrannen/spring-test-junit5#1) the Spring Testing framework should be flexible enough so that this feature could be implemented by the Spock framework. |
Not sure if it's helpful, but thought I'd share in case it was. We are currently using a TestExecutionListener and a base class to allow for having spring beans available in the setupSpec. It has been a while since I looked at it, but if I remember correctly we needed to "tickle" the applicaiton context to make sure Spring loaded it. Not using it for the @shared, so I am not sure if the same applies. Below is an example of the listener and the base class. Base Class@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
@TestExecutionListeners(listeners = [SpringContextInitializingTestExecutionListener])
abstract class BaseSpecification extends Specification {
} Listener/**
* A TestExecutionListener that tickles the Spring application context to ensure that it is initialized in the
* beforeTestClass. This allows us to have the application context initialize before the setupSpec.
*/
class SpringContextInitializingTestExecutionListener extends AbstractTestExecutionListener {
@Override
void beforeTestClass(TestContext testContext) throws Exception {
testContext.applicationContext
}
} |
There is a reason that it is explicitly forbidden to inject into One goal of spock is simplicity, but allowing |
Thanks @leonard84, so this issue can be closed? Or what thoughts do you have? |
As my example above indicates, when we were having trouble with this our biggest desire was to use Spring beans in |
+1 |
This workaround works for me:
|
Actually the example above just calls a static method which does not require autowiring nor functions for setupSpec use-cases for non-static methods as autowiring happens after setupSpec. This is the pattern that I use myself:
|
Thanks Robbert1 for the simple workaround. |
@sskjames read my previous comment |
Thanks @jserranoTWS but is it possible to call an instance method from your version of cleanupSpec?: |
@sskjames, yes, in my example |
Are there any plans for improving this or is official suggestion to use the "poorMansSetupSpec"? |
Is this feature coming any time soon? |
Just thought Id add my workaround to this problem, using Groovy's dynamic goodness:
EDIT: made a Gist: https://gist.github.com/OsaSoft/a2e1ea62f5fc58aec3988e2b8af8bda9 |
@OsaSoft Nice workaround! |
I'm struggling to get an Unroll'd test with Spock using properly injected JpaRepository extended interfaces running. Either nothing is wired when I use @DataJpaTest resulting in the obvious NPE's or Anyone have an idea how this should be set up? |
This worked for me:
|
This is the approach I use:
To use in spec:
|
I'm using something similar to @Chr3is workaround:
|
Following works for me:
No need for closure. |
For a very long time, I thought that allowing injection into My suggestion would be to, instead of having a blanket ban on injection into Why do I personally want to be able to inject into To confirm that injecting into
I'd be more than happy to work on a PR which would enable injection into |
@erdi if you want to create a PR. I was thinking about something like a |
…e which users can opt-in for by adding @EnableSharedInjection to the specification. Fixes spockframework#76.
It would be absolutely great, if Spring's TestContext framework can be extended, so that Spring beans can be injected in @shared fields and can be used in setupSpec() and cleanupSpec().
Thanks, Leif
The text was updated successfully, but these errors were encountered: