Когда примечание Spock @Shared должно быть предпочтительнее статического поля?
Нечего добавить, весь вопрос в заголовке.
Рассмотрим эти два экземпляра класса Foo, используемые в спецификации Spock.
@Shared Foo foo1 = new Foo()
static Foo foo2 = new Foo()
В целом, я знаю идею аннотации @Shared
, но я думаю, что лучше использовать языковые функции, которые в этом случае будут полем static
.
Существуют ли какие-либо конкретные случаи, в которых следует выбирать друг друга или это скорее вопрос вкуса?
Ответы
Ответ 1
Спок - это все о выразительности и ясности.
Статический - это ключевое слово Java, которое отображает только внутренние элементы класса (это поле для всех экземпляров одинаково)
@Shared - это функция Spock, которая говорит читателю, что эта переменная одинакова для всех методов объектов. Это инструкция специально для unit test и делает unit test более понятным для читателя.
То же самое можно сказать и для основных блоков Спока. Если вы думаете об этом, они ничего не меняют в коде.
public void myScenario(){
int a = 2 + 3;
assertEquals(5,a);
}
public void "simple addition scenario"(){
when: "I add two numbers"
int a = 2 +3
then: "I expect the correct result"
a == 5
}
Оба модульных теста выполняют технически то же самое. Второе, однако, более четко показывает намерение. Знаки , когда: и , а затем: ничего не делают с кодом, кроме уточнения его намерения.
Итак, чтобы подвести итог, @Shared делает тест более удобочитаемым. (См. Также @Issue, @Title и т.д., Они существуют с той же целью)
Ответ 2
В отличие от JUnit, где вам нужно объявить переменную поля static и присвоить ей значение в
@BeforeClass
public static void setupClass()
поэтому он был инициализирован только один раз на тестовый набор (не каждый метод), в Spock вы можете использовать переменную поля экземпляра и аннотировать его с помощью @Shared
.
Рассмотрим следующий пример:
class SharedTestSpec extends spock.lang.Specification {
@Shared
def shared = shared()
def shared() {
"I came from ${this.class.simpleName}"
}
def 'Test one'() {
given:
println("test one, shared: $shared")
expect: true
}
def 'Test two'() {
given:
println("test two, shared: $shared")
expect: true
}
}
class SubclassSpec extends SharedTestSpec {
@Override
def shared() {
println("They've got me!")
"I came from ${this.class.simpleName}"
}
}
Запуск SubclassSpec дает вам следующий результат:
test one, shared: I came from SubclassSpec
test two, shared: I came from SubclassSpec
They've got me!
Невозможно объяснить порядок печати, но это из-за AST.
Ответ 3
Как более исчерпывающий подход, здесь приведен пример теста с выходами:
@Unroll
class BasicSpec extends Specification {
int initializedVariable
int globalVariable = 200
static int STATIC_VARIABLE = 300
@Shared
int sharedVariable = 400
void setup() {
initializedVariable = 100
}
void 'no changes'() {
expect:
printVariables()
/*
initializedVariable: 100
globalVariable: 200
STATIC_VARIABLE: 300
sharedVariable: 400
*/
}
void 'change values'() {
setup:
initializedVariable = 1100
globalVariable = 1200
STATIC_VARIABLE = 1300
sharedVariable = 1400
expect:
printVariables()
/*
initializedVariable: 1100
globalVariable: 1200
STATIC_VARIABLE: 1300
sharedVariable: 1400
*/
}
void 'print values again'() {
expect:
printVariables()
/*
initializedVariable: 100
globalVariable: 200
STATIC_VARIABLE: 1300
sharedVariable: 1400
*/
}
private void printVariables() {
println "initializedVariable: $initializedVariable"
println "globalVariable: $globalVariable"
println "STATIC_VARIABLE: $STATIC_VARIABLE"
println "sharedVariable: $sharedVariable\n"
}
}
Удивительная вещь для меня заключается в том, что как переменная в методе класса setup()
AS WELL, так и глобальная, instanced переменная get reset для каждого теста (по-видимому, потому, что класс повторно создается для каждого тестового примера), Между тем переменная static
и @Shared
работает должным образом. В результате последние два могут быть доступны в предложениях where
, которые выполняются перед некоторыми из других, которые перечислены ранее в каждом тестовом случае.