什么时候应该优先使用 Spock 的 @Shared 注释而不是静态字段?
When Spock's @Shared annotation should be preferred over a static field?
没有太多要补充的,整个问题都在标题中。
考虑 Spock 规范中使用的 class Foo 的这两个实例。
@Shared Foo foo1 = new Foo()
static Foo foo2 = new Foo()
总的来说,我知道 @Shared
注释背后的想法,但我想最好使用语言功能,在本例中是 static
字段。
是否有任何特定情况下应该优先选择另一个,或者这更像是一个品味问题?
Spock 就是表现力和清晰度。
Static 是一个 Java 关键字,仅显示 class 的内部结构(该字段对于所有实例都是相同的)
@Shared 是一个 Spock 特性,它告诉 reader 这个变量对于所有特性方法都是相同的。是专门针对单元测试的说明,让reader.
的单元测试更加清晰
主要的 Spock 块也是如此。如果你仔细想想,他们并没有真正改变代码上的任何东西。
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
}
两个单元测试在技术上做完全相同的事情。然而,第二个更清楚地表明了意图。 when: 和 then: 标签除了阐明其意图外,实际上对代码没有任何作用。
总而言之,@Shared 使测试更具可读性。 (另见@Issue、@Title等,它们的存在目的相同)
与 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。
作为一种更详尽的方法,这是一个带有输出的示例测试:
@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"
}
}
令我惊讶的是,class' setup()
方法中的变量以及全局实例变量在每次测试时都会重置(大概是因为 class 为每个测试用例重新实例化)。同时,static
和 @Shared
变量按预期工作。因此,后两者也可以在 where
子句中访问,这些子句在每个测试用例中列出的其他一些子句之前 运行。
静态字段只能用于常量。否则共享字段更可取,因为它们关于共享的语义定义更明确。
没有太多要补充的,整个问题都在标题中。
考虑 Spock 规范中使用的 class Foo 的这两个实例。
@Shared Foo foo1 = new Foo()
static Foo foo2 = new Foo()
总的来说,我知道 @Shared
注释背后的想法,但我想最好使用语言功能,在本例中是 static
字段。
是否有任何特定情况下应该优先选择另一个,或者这更像是一个品味问题?
Spock 就是表现力和清晰度。
Static 是一个 Java 关键字,仅显示 class 的内部结构(该字段对于所有实例都是相同的)
@Shared 是一个 Spock 特性,它告诉 reader 这个变量对于所有特性方法都是相同的。是专门针对单元测试的说明,让reader.
的单元测试更加清晰主要的 Spock 块也是如此。如果你仔细想想,他们并没有真正改变代码上的任何东西。
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
}
两个单元测试在技术上做完全相同的事情。然而,第二个更清楚地表明了意图。 when: 和 then: 标签除了阐明其意图外,实际上对代码没有任何作用。
总而言之,@Shared 使测试更具可读性。 (另见@Issue、@Title等,它们的存在目的相同)
与 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。
作为一种更详尽的方法,这是一个带有输出的示例测试:
@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"
}
}
令我惊讶的是,class' setup()
方法中的变量以及全局实例变量在每次测试时都会重置(大概是因为 class 为每个测试用例重新实例化)。同时,static
和 @Shared
变量按预期工作。因此,后两者也可以在 where
子句中访问,这些子句在每个测试用例中列出的其他一些子句之前 运行。
静态字段只能用于常量。否则共享字段更可取,因为它们关于共享的语义定义更明确。