Вы можете решить проблему с помощью data
, используя этот подход:
data << dataReader.parse('JobE2E', "${getClass().name}.json", 'My first test')
Он будет повторять список карт, поэтому каждая итерация теста будет параметризована только этой картой.
Текущее название теста можно получить:
specificationContext.currentFeature.name
И имя текущей итерации:
specificationContext.currentIteration.name
Но оба они недоступны в разделе where
, поскольку он выполняется перед самим тестом, где доступны только значения из общего контекста. Так что здесь я боюсь, что вам нужно вводить название теста вручную.
Обновление: Я нашел решение, как получить имя функции в разделе where
для вас. Реализуется собственным расширением с использованием перехватчика.
Особенности контейнера деталей:
class FeatureDetails {
String name
}
Расширение аннотации:
import org.spockframework.runtime.extension.ExtensionAnnotation
import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ExtensionAnnotation(FeatureDetailsExtension.class)
@interface ShareFeatureDetails {
}
Расширение спока с реализацией встроенного перехватчика:
import org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension
import org.spockframework.runtime.model.FeatureInfo
class FeatureDetailsExtension extends AbstractAnnotationDrivenExtension<ShareFeatureDetails> {
def featureDetails = new FeatureDetails()
@Override
void visitFeatureAnnotation(ShareFeatureDetails annotation, FeatureInfo feature) {
feature.addInterceptor({ i ->
featureDetails.name = feature.name
feature.spec.allFields.each { f ->
if (f.type == FeatureDetails.class && f.readValue(i.getInstance()) == null) {
f.writeValue(i.getInstance(), featureDetails)
}
}
i.proceed()
})
}
}
Пример использования расширения:
class DataProviderSpec extends Specification {
@Shared
FeatureDetails currentFeature
@Unroll("Test #data.a * 2 = #data.b")
@ShareFeatureDetails
def 'test'() {
when:
println data
then:
data.a * 2 == data.b
where:
data << loadData()
}
@Unroll("Test #data.a * 3 = #data.b")
@ShareFeatureDetails
def 'another test'() {
when:
println data
then:
data.a * 3 == data.b
where:
data << loadData()
}
def loadData() {
// this is hard coded example
println "${getClass().name}.${currentFeature.name}"
if ('test' == currentFeature.name) return [[a: 1, b: 2], [a: 2, b: 4]]
if ('another test' == currentFeature.name) return [[a: 3, b: 9], [a: 4, b: 12]]
return []
// ... use load from data file (JSON, YAML, XML, ...) instead:
// return dataReader.parse("${getClass().name}.json", currentFeature.name)
}
}
И вывод приведенного выше примера:
DataProviderSpec.test
[a: 1, b: 2]
[a: 2, b: 4]
DataProviderSpec.another тест
[a: 3, b: 6]
[a: 4, b: 8]
Первой идеей было использование только аннотированного поля String featureName
в классе спецификации, но существует проблема, когда метод visitFeatureAnnotation()
работает с различным экземпляром спецификации во время каждого вызова, тогда как метод loadData()
выполняется каждый раз в первом экземпляре.
Примечание: Вы также можете добавить описание со значениями, относящимися к текущей итерации, используя аннотацию @Unroll
. Например:
@Unroll("Test #data.a * 2 = #data.b")
def 'test'() {
setup:
...
when:
...
then:
data.a * 2 == data.b
where:
data << getData('test')
}
def getData(String methodName) {
if ('test' == methodName) return [[a: 1, b: 2], [a: 2, b: 4]]
...
}
Будет производить:
Тест 1 * 2 = 2
Тест 2 * 2 = 4