当Spock的@Shared注释比静态字段更受欢迎时?

时间:2016-03-10 17:49:18

标签: unit-testing groovy spock

没有太多补充,整个问题都在标题中。

考虑Spock规范中使用的这两个Foo类实例。

@Shared Foo foo1 = new Foo()

static Foo foo2 = new Foo()

总的来说,我知道@Shared注释背后的想法,但我认为使用语言功能会更好,在这种情况下会是static字段。

是否有任何特定的案例,其中一个人应该优先于另一个,或者它是一个品味问题?

4 个答案:

答案 0 :(得分:13)

Spock完全是关于表现力清晰度

静态是一个Java关键字,仅显示类的内部(此字段对所有实例都相同)

@Shared 是一个Spock功能,它向读者说明这个变量对于所有要素方法都是相同的。它是专门针对单元测试的指令,使读者可以更清楚地进行单元测试。

主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 等,它们存在的目的相同)

答案 1 :(得分:9)

与JUnit相反,您必须在

中声明字段变量静态并为其赋值
@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。

答案 2 :(得分:1)

作为一种更详尽的方法,这是一个带有输出的样本测试:

@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,因为全局的实例变量在每次测试时都会重置(可能是因为每个测试用例都重新实例化了类)。同时,static@Shared变量按预期工作。因此,后两者也可以在where子句中访问,这些子句在每个测试用例之前列出的其他一些子句之前运行。

答案 3 :(得分:0)

静态字段只能用于常量。否则,共享字段是更可取的,因为它们在共享方面的语义更加明确。