先介绍一下两位主角
spock
是一款基于Groovy语言的单元测试框架,其基础也是Java
的Junit
,目前最新版已经到了2.0
,但对Groovy
和响应的Java
版本要求较高,具体信息参考:Spock 2.0 M1版本初探。
Mockito
是一个模拟测试框架,可以让你用优雅,简洁的接口写出漂亮的单元测试。Mockito可以让单元测试易于可读,产生简洁的校验错误。TDD测试驱动开发要求我们先写单元测试,再写实现代码。在写单元测试的过程中,由于各种依赖的关系导致的阻碍,我们必需用到Mockito
类似的框架来完成资源、对象的模拟。
Gradle配置
代码语言:javascript复制 testCompile 'org.mockito:mockito-core:2.7.22'
testCompile group: 'org.spockframework', name: 'spock-core', version: '1.3-groovy-2.5'
testCompile group: 'org.springframework', name: 'spring-test', version: '5.1.9.RELEASE'
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '2.0.0'
testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.2'
Demo代码
下面是演示代码:
代码语言:javascript复制package com.FunTester.mockito.practise
import org.apache.http.client.methods.HttpRequestBase
import org.slf4j.Logger
import spock.lang.Shared
import spock.lang.Specification
import static com.fun.config.Constant.SPACE_1
import static com.fun.frame.SourceCode.getLogger
import static org.mockito.AdditionalAnswers.returnsFirstArg
import static org.mockito.Matchers.anyInt
import static org.mockito.Mockito.*
class Demo extends Specification {
@Shared
Logger logger = getLogger(this.getClass().getName())
@Shared
List listsss = mock(List)
@Shared
HttpRequestBase httpRequestBase = mock(HttpRequestBase.class)
def setup() {
logger.info("测试方法开始了")
}
def cleanup() {
logger.info("测试方法结束了")
}
def setupSpec() {
logger.info("测试类[${getClass().getName()}]开始了")
}
def cleanupSpec() {
logger.info("测试类[${getClass().getName()}]结束了")
}
def "这是一个普通的demo"() {
given:"创建一个存根list,添加一些元素"
List mockedList = mock(List.class);
mockedList.add("one");
mockedList.add("two");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");
when(mockedList.size()).thenReturn(5);
mockedList.add("3")
mockedList.add("3")
mockedList.add("3")
mockedList.add("3")
expect:"验证属性以及方法调用次数"
5 == mockedList.size()
false == verify(mockedList, atLeastOnce()).add("one")
false == verify(mockedList, times(3)).add("three times")
false == verify(mockedList, atMost(4)).add("3")
false == verify(mockedList, never()).add("30")
}
def "这是一个测试的mockito模拟方法返回"() {
given: "虚拟一个迭代器对象"
def iterator = mock(Iterator.class)
when(iterator.next()).thenReturn("hello").thenReturn("world")
expect: "测试迭代器元素拼接"
"hello world" == iterator.next() SPACE_1 iterator.next()
}
def "这是一个测试,用来在对象初始化之后mock对象的"() {
given: "创建对象后再Mockito"
def iterator = new ArrayList()
iterator.add("323")
def list = spy(iterator)
doReturn("fun").when(list).get(3)
doReturn(3).when(list).get(0)
expect:
list.contains("323")
"fun" == list.get(3)
3 == list.get(0)
}
def "这是一个测试,抛出异常的测试用例"() {
given: "创建测试对象"
def object = mock(ArrayList.class)
when(object.get(1)).thenThrow(new IndexOutOfBoundsException("我是测试"))//只能抛出可能的抛出的异常
def re = 0
try {
object.get(1)
} catch (IndexOutOfBoundsException e) {
re = 1
}
expect:
re == 1
}
def "这是一个测试方法返回值的用例"() {
given:
def j = mock(DemoJ.class)
doAnswer(returnsFirstArg()).when(j).ds(anyInt(), anyInt())
// when(list.add(anyString())).thenAnswer(returnsFirstArg());
// with then() alias:
// when(list.add(anyString())).then(returnsFirstArg());
expect:
3 == j.ds(3, 32)
}
def "我是测试共享Mock对象的用例"() {
given:
when(listsss.get(anyInt())).thenReturn(3)
expect:
3 == listsss.get(3)
}
/**
* 对于未指定mock的方法,spy默认会调用真实的方法,有返回值的返回真实的返回值,而mock默认不执行,有返回值的,默认返回null
*/
def "spy和mock区别"() {
given:
def list = [1,2,3,4]
def integers = spy(list)
when(integers.size()).thenReturn(9)
expect:
integers.size() == 9
integers.get(0) == 1
}
}
- 经过我的测试,
Mockito
的基础功能在spock
应用还是非常流畅的,但是一些高级语法还是无法使用,如果在实际项目中使用请多调研两者差别,大概率还是要混合编程。
参考文章:
- Maven和Gradle中配置单元测试框架Spock
- Groovy单元测试框架spock基础功能Demo
- Groovy单元测试框架spock数据驱动Demo
- 郑重声明:“FunTester”首发,欢迎关注交流,禁止第三方转载。更多原创文章:FunTester十八张原创专辑,合作请联系
Fhaohaizi@163.com
。