specification 来源于近期流行起来写的
BDD(Behavior-driven development 行为驱动测试)
。在TDD的基础上,通过测试来表达代码的行为。通过某种规范说明语言去描述程序“应该”做什么,再通过一个测试框架读取这些描述、并验证应用程序是否符合预期。把需求转化成Given/When/Then的三段式,所以你看到测试框架有这种Given/When/Then三段式语法的,一般来说背后都是BDD思想,比如上图中的Cucumber和JBehave。
Spock快速使用
现在让我们以最快速的方式,来使用一次Spock
3.0 创建一个空白项目
创建一个空白项目:
spock-example
,选择maven工程。
3.1 依赖
<dependencies><!-- Mandatory dependencies for using Spock --><!-- 使用Spock必须的依赖 --><dependency><groupId>org.spockframework</groupId><artifactId>spock-core</artifactId><version>1.3-groovy-2.5</version><scope>test</scope></dependency><!-- Optional dependencies for using Spock --><!-- 选择性使用的Spock相关依赖 --><dependency><!-- use a specific Groovy version rather than the one specified by spock-core --><!-- 不使用Spock-core中定义的Groovy版本,而是自己定义 --><groupId>org.codehaus.groovy</groupId><artifactId>groovy-all</artifactId><version>2.5.7</version><type>pom</type></dependency><dependency><!-- enables mocking of classes (in addition to interfaces) --><!-- mock 接口和类时要用 --><groupId>net.bytebuddy</groupId><artifactId>byte-buddy</artifactId><version>1.9.3</version><scope>test</scope></dependency><dependency><!-- enables mocking of classes without default constructor (together with CGLIB) --><!-- mock 类要用 --><groupId>org.objenesis</groupId><artifactId>objenesis</artifactId><version>2.6</version><scope>test</scope></dependency><dependency><!-- only required if Hamcrest matchers are used --><!-- Hamcrest 是一个用于编写匹配对象的框架,如果用到了Hamcrest matchers,需要加这个依赖 --><groupId>org.hamcrest</groupId><artifactId>hamcrest-core</artifactId><version>1.3</version><scope>test</scope></dependency><!-- Dependencies used by examples in this project (not required for using Spock) --><!-- 使用h2base做测试数据库--><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><version>1.4.197</version><scope>test</scope></dependency></dependencies>
3.2 插件
<plugins><!-- Mandatory plugins for using Spock --><!--使用Spock的强制性插件 --><plugin><!-- The gmavenplus plugin is used to compile Groovy code. To learn more about this plugin,visit https://github.com/groovy/GMavenPlus/wiki --><!-- 这个 gmavenplus 插件是用于编译Groovy代码的 . 想获取更多此插件相关信息,visit https://github.com/groovy/GMavenPlus/wiki --><groupId>org.codehaus.gmavenplus</groupId><artifactId>gmavenplus-plugin</artifactId><version>1.6</version><executions><execution><goals><goal>compile</goal><goal>compileTests</goal></goals></execution></executions></plugin><!-- Optional plugins for using Spock --><!-- 选择性使用的Spock相关插件--><!-- Only required if names of spec classes don't match default Surefire patterns (`*Test` etc.) --><!--只有当测试类不匹配默认的 Surefire patterns (`*Test` 等等.)--><plugin><artifactId>maven-surefire-plugin</artifactId><version>2.20.1</version><configuration><useFile>false</useFile><includes><include>**/*Test.java</include><include>**/*Spec.java</include></includes></configuration></plugin></plugins>
*
@author
Richard_yyf
*
@version
1.0 2019/10/1
public
class
Calculator
{
public
int
size
(String str)
{
return
str.length();
public
int
sum
(
int
a,
int
b)
{
return
a + b;
3.5 创建测试类
Ctrl + Shift + T
import spock.lang.Specification
import spock.lang.Subject
import spock.lang.Title
import spock.lang.Unroll
* @author Richard_yyf
* @version
1.0 2019/10/1
@Title("测试计算器类")
@Subject(Calculator)
classCalculatorSpecextendsSpecification {def calculator = new Calculator()
void setup() {
void cleanup() {
def"should return the real size of the input string"() {
expect:
str.size() == length
where:
str | length
"Spock" | 5"Kirk" | 4"Scotty" | 6// 测试不通过def"should return a+b value"() {
expect:
calculator.sum(1,1) == 1// 不建议用中文哦@Unrolldef"返回值为输入值之和"() {
expect:
c == calculator.sum(a, b)
where:
a | b | c
1 | 2 | 32 | 3 | 510 | 2 | 12
classPublisherSpecextendsSpecification {
Publisher publisher = new Publisher()
Subscriber subscriber = Mock()
Subscriber subscriber2 = Mock()
def setup() {
publisher.subscribers << subscriber // << is a Groovy shorthand for List.add()
publisher.subscribers << subscriber2
调用频率约束(cardinality)
1 * subscriber.receive("hello") // exactly one call0 * subscriber.receive("hello") // zero calls
(1..3) * subscriber.receive("hello") // between one and three calls (inclusive)
(1.._) * subscriber.receive("hello") // at least one call
(_..3) * subscriber.receive("hello") // at most three calls
_ * subscriber.receive("hello") // any number of calls, including zero// (rarely needed; see 'Strict Mocking')
目标约束(target constraint)
1 * subscriber.receive("hello") // a call to 'subscriber'1 * _.receive("hello") // a call to any mock object
方法约束(method constraint)
1 * subscriber.receive("hello") // a method named 'receive'1 * subscriber./r.*e/("hello") // a method whose name matches the given regular expression (here: method name starts with 'r' and ends in 'e')
参数约束(argument constraint)
1 * subscriber.receive("hello") // an argument that is equal to the String "hello"1 * subscriber.receive(!"hello") // an argument that is unequal to the String "hello"1 * subscriber.receive() // the empty argument list (would never match in our example)1 * subscriber.receive(_) // any single argument (including null)1 * subscriber.receive(*_) // any argument list (including the empty argument list)1 * subscriber.receive(!null) // any non-null argument1 * subscriber.receive(_ as String) // any non-null argument that is-a String1 * subscriber.receive(endsWith("lo")) // any non-null argument that is-a String1 * subscriber.receive({ it.size() > 3 && it.contains('a') })
// an argument that satisfies the given predicate, meaning that// code argument constraints need to return true of false// depending on whether they match or not// (here: message length is greater than 3 and contains the character a)