Reputation: 113
Spock has setupSpec
on the Spec class level. I would want to have something similar for a single test case level.
This might not be available in Spock, Does someone has a workaround for this.
void "test something"() {
setup:
User user = createUser()
when:
user.setAdress(new Address(zipCode: inputZipCode, city: inputCity))
then:
user.address.city == inputCity
user.address.zipCode == inputZipCode
cleanup:
deleteUser(user)
where:
inputCity | inputZipCode
"a" |"1"
"b" |"2"
}
Creating and deleting user is unnecessarily done after every iteration.
Could it be possible to have something la- setupSpec
for a single test instead of class-level?
It is possible to manipulate the test cases to use class-setupSpec/CleanupSpec or even create a new test (with @Stepwise) to achieve this but I am looking for something good solution not a hack.
Upvotes: 1
Views: 427
Reputation: 67317
I think this is very ugly because it involves manual bookkeeping. I do not recommend you to do it like this, but anyway:
package de.scrum_master.stackoverflow.q57721328
import spock.lang.See
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll
class OneTimeSetupCleanupParametrisedTest extends Specification {
@Shared User user
@Shared int iteration
User createUser() {
// Set up test fixture only if iteration == 0 (or optionally, if fixture is uninitialised)
user ?: new User()
}
void deleteUser(User userInstance) {
// Clean up counter (and test fixture, if any) only if iteration == total number of iterations
if (++iteration == specificationContext.currentIteration.estimatedNumIterations) {
userInstance.delete()
user = null
iteration = 0
}
}
// @Unroll
void "test something"() {
setup:
// Call initialiser helper for each iteration, relying on the fact that it will only
// create a text fixture if none exists yet
user = createUser()
when:
user.setAdress(new Address(zipCode: inputZipCode, city: inputCity))
then:
user.address.city == inputCity
user.address.zipCode == inputZipCode
cleanup:
// Call clean-up helper for each iteration, relying on the fact that it will only
// clean up the fixture during the last iteration
deleteUser(user)
where:
inputCity | inputZipCode
"a" | "1"
"b" | "2"
}
static class User {
Address address
User() {
println "creating user"
}
void setAdress(Address address) {
this.address = address
}
void delete() {
println "deleting user"
address = null
}
}
static class Address {
String zipCode, city
}
}
Console log:
creating user
deleting user
Update: The Spock manual says about this topic:
Sharing of Objects between Iterations
In order to share an object between iterations, it has to be kept in a @Shared or static field.
NOTE: Only
@Shared
andstatic
variables can be accessed from within awhere:
block.Note that such objects will also be shared with other methods. There is currently no good way to share an object just between iterations of the same method. If you consider this a problem, consider putting each method into a separate spec, all of which can be kept in the same file. This achieves better isolation at the cost of some boilerplate code.
Upvotes: 2