找到你要的答案

Q:How can I reuse some parts of my tests?

Q:我如何重用我的测试的某些部分?

I need to implement following logic:

  1. Do something
  2. Check logic
  3. Do something other
  4. Similar check logic

I used when/then blocks for simple tests. But I really don't know how to implement more complicated one (like described above) + I would like to reuse code as much as possible. But with blocks it becomes more complicated to implement

我需要实现以下逻辑:

  1. Do something
  2. Check logic
  3. Do something other
  4. Similar check logic

我用/然后块进行简单的测试。但我真的不知道如何实现更复杂的一个(如上所述)+我想重用代码尽可能。但随着块的实施变得更加复杂

answer1: 回答1:

There are a few approaches I take to reusing code in Spock.

Feature Level Create a closure within your setup: block. You can treat it like a method that's available to only this feature.

def "test"() {
    setup:
        def containsCat = {String it -> it.contains('cat')}
    expect:
        !containsCat('I love my dog')
        containsCat('I love my cat')
}

def "test that cannot reference containsCat(String)"() {
    // Test stuff
} 

Spec Class Level While it is possible to use a @Shared closure, my preference is to use private helper methods unless the helper logic is just one or two lines.

class tester extends Specification {
@Shared
def containsDog = {String it -> it.contains('dog')}
private containsCat(String inputString) {
    inputString.contains('cat')
}

def "test"(String myPet) {
    expect: containsCat(myPet)
    where: myPet = 'I love my cat'
}

def "test2"() {
    expect: containsDog(mySistersPet)
    where: mySistersPet = 'I love my dog'
}

Package Level
I have a group of classes that could all benefit from sharing a miniature testing framework. My preference is to use traits. They can hold any code except for a Feature test itself. If the trait will reference data from within the test itself, make sure to create an abstract method so the trait is ensured a reference to the data.

trait petTester {
    private containsDog(String inputString) {
        inputString.contains('dog')
    }    
    private containsCat(String inputString) {
        inputString.contains('cat')
    }    
}

class myPetTester extends Specification implements petTester {
    def "test"(String myPet) {
        expect: containsCat(myPet)
        where: myPet = 'I love my cat'
    }
}

class mySistersPetTester extends Specification implements petTester {
    def "test2"() {
        expect: containsDog(mySistersPet)
        where: mySistersPet = 'I love my dog'
    }    
}

有几个方法我重用代码在斯波克。

Feature Level Create a closure within your setup: block. You can treat it like a method that's available to only this feature.

def "test"() {
    setup:
        def containsCat = {String it -> it.contains('cat')}
    expect:
        !containsCat('I love my dog')
        containsCat('I love my cat')
}

def "test that cannot reference containsCat(String)"() {
    // Test stuff
} 

Spec Class Level While it is possible to use a @Shared closure, my preference is to use private helper methods unless the helper logic is just one or two lines.

class tester extends Specification {
@Shared
def containsDog = {String it -> it.contains('dog')}
private containsCat(String inputString) {
    inputString.contains('cat')
}

def "test"(String myPet) {
    expect: containsCat(myPet)
    where: myPet = 'I love my cat'
}

def "test2"() {
    expect: containsDog(mySistersPet)
    where: mySistersPet = 'I love my dog'
}

Package Level
I have a group of classes that could all benefit from sharing a miniature testing framework. My preference is to use traits. They can hold any code except for a Feature test itself. If the trait will reference data from within the test itself, make sure to create an abstract method so the trait is ensured a reference to the data.

trait petTester {
    private containsDog(String inputString) {
        inputString.contains('dog')
    }    
    private containsCat(String inputString) {
        inputString.contains('cat')
    }    
}

class myPetTester extends Specification implements petTester {
    def "test"(String myPet) {
        expect: containsCat(myPet)
        where: myPet = 'I love my cat'
    }
}

class mySistersPetTester extends Specification implements petTester {
    def "test2"() {
        expect: containsDog(mySistersPet)
        where: mySistersPet = 'I love my dog'
    }    
}
answer2: 回答2:

You can use interaction { doStuff() } too.

However, if you find that your doStuff() is large and that many of your tests are using the same interaction method then it might be time to think about moving some code in your production class into a separate class and then having one expectation that your class under test calls your new class.

你可以使用交互dostuff() } {太。

然而,如果你发现你的dostuff()大和你的许多测试都使用相同的交互方法,那么也许是时候考虑将一些代码在您的生产类在一个单独的类,然后有一个期望,你的被测试的类调用新类。

answer3: 回答3:

If you want to run the same test twice, just changing some parameters, you can use where:

  def "foo"(Boolean barIsEnabled) {
      when:
      myService.testBar(barIsEnabled)

      then:
      myService.readBar() == "123456"

      where: "this code shoud work with bar enabled or disabled"
      barIsEnabled  | ignored
      true          | _
      false         | _
  }  

Ref: http://spockframework.github.io/spock/docs/1.0/data_driven_testing.html

If you just want to reuse the then logic, create a private method and add many assert inside it:

def "foo"() {
  when:
  def pc = shop.buyPc()

  then:
  matchesPreferredConfiguration(pc)
}
void matchesPreferredConfiguration(pc) {
  assert pc.vendor == "Sunny"
  assert pc.clockRate >= 2333
  assert pc.ram >= 4096
  assert pc.os == "Linux"
}

Ref: http://spockframework.github.io/spock/docs/1.0/spock_primer.html#_helper_methods

如果你想运行相同的测试两次,只是改变一些参数,您可以使用:

  def "foo"(Boolean barIsEnabled) {
      when:
      myService.testBar(barIsEnabled)

      then:
      myService.readBar() == "123456"

      where: "this code shoud work with bar enabled or disabled"
      barIsEnabled  | ignored
      true          | _
      false         | _
  }  

参考:http://spockframework.github.io/spock/docs/1.0/data_driven_testing.html

如果只想重用逻辑,则创建一个私有方法,并在其中添加许多断言:

def "foo"() {
  when:
  def pc = shop.buyPc()

  then:
  matchesPreferredConfiguration(pc)
}
void matchesPreferredConfiguration(pc) {
  assert pc.vendor == "Sunny"
  assert pc.clockRate >= 2333
  assert pc.ram >= 4096
  assert pc.os == "Linux"
}

参考:HTTP:/ / spockframework。GitHub。IO /斯波克/文档/ 1 / spock_primer HTML # _helper_methods。

testing  groovy  spock