赞
踩
从简单到困难,一步步教你用Spock写单元测试。
首先,你需要在你的项目中安装Spock。如果你使用的是Gradle,可以在build.gradle
文件中添加以下依赖:
testImplementation 'org.spockframework:spock-core:2.0-M3-groovy-3.0'
如果你使用的是Maven,可以在pom.xml
文件中添加以下依赖:
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>2.0-M3-groovy-3.0</version>
<scope>test</scope>
</dependency>
接下来,让我们编写一个简单的测试。假设我们有一个名为Calculator
的类,其中有一个add
方法,用于将两个数字相加。我们想要测试这个方法是否正确地计算了结果。
我们可以创建一个名为CalculatorSpec
的类,其中包含以下代码:
import spock.lang.Specification
class CalculatorSpec extends Specification {
def "test add method"() {
given:
Calculator calculator = new Calculator()
when:
def result = calculator.add(2, 3)
then:
result == 5
}
}
在这个测试中,我们使用了Spock的BDD(行为驱动开发)语法。我们使用given
块初始化测试数据,when
块执行我们要测试的方法,then
块验证结果是否符合预期。
接下来,让我们使用数据驱动测试来测试add
方法。我们可以使用Spock的where
块来定义测试数据,如下所示:
import spock.lang.Specification class CalculatorSpec extends Specification { def "test add method"() { given: Calculator calculator = new Calculator() when: def result = calculator.add(a, b) then: result == expected where: a | b | expected 2 | 3 | 5 5 | 7 | 12 10 | 0 | 10 } }
在这个测试中,我们使用了where
块来定义测试数据。我们定义了三组输入数据和预期输出结果,Spock会自动运行这些数据并验证结果是否符合预期。
接下来,让我们使用Mock对象来测试Calculator
类。假设Calculator
类依赖于一个名为MathService
的服务,我们想要测试Calculator
类是否正确地使用了这个服务。
我们可以使用Spock的Mock对象来模拟MathService
服务,如下所示:
import spock.lang.Specification import spock.lang.Mock class CalculatorSpec extends Specification { @Mock MathService mathService def "test add method"() { given: Calculator calculator = new Calculator(mathService) when: def result = calculator.add(2, 3) then: result == 5 1 * mathService.add(2, 3) >> 5 } }
在这个测试中,我们使用了Spock的@Mock
注解来创建一个MathService
的Mock对象。我们还使用了1 * mathService.add(2, 3) >> 5
语法来指定当mathService.add(2, 3)
方法被调用时返回5。
最后,让我们使用交互测试来测试Calculator
类是否正确地调用了MathService
服务。我们可以使用Spock的@Unroll
注解来展开测试结果,如下所示:
import spock.lang.Specification import spock.lang.Mock import spock.lang.Unroll class CalculatorSpec extends Specification { @Mock MathService mathService def "test add method"() { given: Calculator calculator = new Calculator(mathService) when: def result = calculator.add(a, b) then: result == expected 1 * mathService.add(a, b) >> expected @Unroll "a=#a, b=#b, expected=#expected": [a: 2, b: 3, expected: 5], [a: 5, b: 7, expected: 12], [a: 10, b: 0, expected: 10] } }
在这个测试中,我们使用了@Unroll
注解来展开测试结果,这样我们就可以看到每组测试数据的结果。我们还使用了1 * mathService.add(a, b) >> expected
语法来指定当mathService.add(a, b)
方法被调用时返回expected
值。
@Shared
注解在Spock中,每个测试方法都会创建一个新的测试实例。如果测试中有多个测试方法,每个方法都会创建一个新的实例,这可能会导致测试运行速度变慢。为了避免这种情况,我们可以使用@Shared
注解来创建一个实例,该实例在所有测试方法之间共享。
例如,我们可以在CalculatorSpec
类中使用@Shared
注解来创建一个共享的Calculator
对象,如下所示:
import spock.lang.Specification import spock.lang.Mock import spock.lang.Unroll class CalculatorSpec extends Specification { @Shared Calculator calculator = new Calculator() @Mock MathService mathService def "test add method"() { given: Calculator calculator = new Calculator(mathService) when: def result = calculator.add(a, b) then: result == expected 1 * mathService.add(a, b) >> expected @Unroll "a=#a, b=#b, expected=#expected": [a: 2, b: 3, expected: 5], [a: 5, b: 7, expected: 12], [a: 10, b: 0, expected: 10] } }
在这个测试中,我们使用了@Shared
注解来创建一个共享的Calculator
对象,这样在所有测试方法之间都可以使用相同的对象。
@Ignore
注解有时候,我们可能需要暂时忽略某个测试方法,例如当我们正在解决某个bug时。我们可以使用@Ignore
注解来暂时忽略某个测试方法,如下所示:
import spock.lang.Specification import spock.lang.Mock import spock.lang.Unroll class CalculatorSpec extends Specification { @Shared Calculator calculator = new Calculator() @Mock MathService mathService def "test add method"() { given: Calculator calculator = new Calculator(mathService) when: def result = calculator.add(a, b) then: result == expected 1 * mathService.add(a, b) >> expected @Unroll "a=#a, b=#b, expected=#expected": [a: 2, b: 3, expected: 5], [a: 5, b: 7, expected: 12], [a: 10, b: 0, expected: 10] } @Ignore def "test subtract method"() { given: Calculator calculator = new Calculator() when: def result = calculator.subtract(a, b) then: result == expected where: a | b | expected 5 | 3 | 2 10 | 5 | 5 15 | 7 | 8 } }
在这个测试中,我们使用了@Ignore
注解来暂时忽略test subtract method
测试方法。
@Timeout
注解有时候,我们可能需要限制测试方法的执行时间,以避免测试运行时间过长。我们可以使用@Timeout
注解来限制测试方法的执行时间,如下所示:
import spock.lang.Specification import spock.lang.Mock import spock.lang.Unroll class CalculatorSpec extends Specification { @Shared Calculator calculator = new Calculator() @Mock MathService mathService @Timeout(1000) def "test add method"() { given: Calculator calculator = new Calculator(mathService) when: def result = calculator.add(a, b) then: result == expected 1 * mathService.add(a, b) >> expected @Unroll "a=#a, b=#b, expected=#expected": [a: 2, b: 3, expected: 5], [a: 5, b: 7, expected: 12], [a: 10, b: 0, expected: 10] } }
在这个测试中,我们使用了@Timeout(1000)
注解来限制test add method
测试方法的执行时间为1秒。如果测试方法超过了指定的时间,测试将会失败。
@Stepwise
注解有时候,我们可能需要按顺序执行测试方法,以确保测试的正确性。我们可以使用@Stepwise
注解来按顺序执行测试方法,如下所示:
import spock.lang.Specification import spock.lang.Mock import spock.lang.Unroll @Stepwise class CalculatorSpec extends Specification { @Shared Calculator calculator = new Calculator() @Mock MathService mathService def "test add method"() { given: Calculator calculator = new Calculator(mathService) when: def result = calculator.add(a, b) then: result == expected 1 * mathService.add(a, b) >> expected @Unroll "a=#a, b=#b, expected=#expected": [a: 2, b: 3, expected: 5], [a: 5, b: 7, expected: 12], [a: 10, b: 0, expected: 10] } def "test subtract method"() { given: Calculator calculator = new Calculator() when: def result = calculator.subtract(a, b) then: result == expected where: a | b | expected 5 | 3 | 2 10 | 5 | 5 15 | 7 | 8 } }
在这个测试中,我们使用了@Stepwise
注解来按顺序执行测试方法。首先执行test add method
测试方法,然后执行test subtract method
测试方法。如果test add method
测试方法失败,test subtract method
测试方法将不会执行。
@IgnoreRest
注解有时候,我们可能需要在测试方法失败后停止执行后续测试方法,以避免测试结果受到之前测试方法的影响。我们可以使用@IgnoreRest
注解来在测试方法失败后停止执行后续测试方法,如下所示:
import spock.lang.Specification import spock.lang.Mock import spock.lang.Unroll class CalculatorSpec extends Specification { @Shared Calculator calculator = new Calculator() @Mock MathService mathService def "test add method"() { given: Calculator calculator = new Calculator(mathService) when: def result = calculator.add(a, b) then: result == expected 1 * mathService.add(a, b) >> expected @Unroll "a=#a, b=#b, expected=#expected": [a: 2, b: 3, expected: 5], [a: 5, b: 7, expected: 12], [a: 10, b: 0, expected: 10] } @IgnoreRest def "test subtract method"() { given: Calculator calculator = new Calculator() when: def result = calculator.subtract(a, b) then: result == expected where: a | b | expected 5 | 3 | 3 10 | 5 | 5 15 | 7 | 8 } def "test divide method"() { given: Calculator calculator = new Calculator() when: def result = calculator.divide(a, b) then: result == expected where: a | b | expected 10 | 2 | 5 20 | 4 | 5 30 | 5 | 6 } }
在这个测试中,我们使用了@IgnoreRest
注解来在test subtract method
测试方法失败后停止执行后续测试方法。如果test subtract method
测试方法失败,test divide method
测试方法将不会执行。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。