Java中Spock框架Mock对象的方法经验总结

网友投稿 529 2022-08-26


Java中Spock框架Mock对象的方法经验总结

目录一、技术方案二、非静态资源三、Mock被测对象1.@Autowired构造方法2.@Autowired属性对象,无构造方法3.PowerMock用法4.共享对象以及初始化四、定义对象行为1.Spock定义Mock对象行为2.Mockito模拟对象行为

前言:

下面分享一些使用过的一个常用项目,部分信息隐去了。大家在自己项目中实践的时候可以参考,尽量别直接抄代码,我自己使用过程中有很多兼容性的坑,特别是IDE自动import功能。

一、技术方案

本技术方案基于公司力推的Spock单元测试框架,spock是一款基于Groovy语言的单元测试框架,其基础也是java的Junit,目前最新版已经到了2.0,但对Groovy和相应的Java版本要求较高,所以Groovy版本使用1.+,Spock自带的Mock和Spy足够好了,对于对象行为的模拟满http://足绝大部分场景,但是涉及静态方法模拟时候存在局限性,所以引入Mockito和PowerMock来实现设计静态方法的测试模拟场景。

以下为相关依赖版本:

org.spockframework

spock-core

1.2-groovy-2.5

test

org.spockframework

spock-spring

1.2-groovy-2.5

test

org.powermock

powermock-api-mockito2

1.7.4

test

org.powermock

powermock-module-junit4

1.7.4

test

org.mockito

mockito-core

2.8.9

test

因为Spock本身需要Groovy语言支持,所以也需要一个Groovy-all的依赖,请注意注自带的注释:

org.codehaus.groovy

groovy-all

2.4.7

另外,提供的配置文件中多了几项特殊场景下使用的依赖,提供参考:

net.bytebuddy

byte-buddy

1.9.9

test

org.objenesis

objenesis

3.0.1

test

org.hamcrest

hamcrest-core

2.1

test

二、非静态资源

由于多个单测框架的方法名重复较多,我把import内容也贴出来了,如果同样的代码无法运行,可以排查一下是否import正确的方法和类。这里不是很建议import static ,因为可能出现混用以及不易排查的问题。

由于目前测试中没有遇到使用Spy放行的逻辑,所以均使用Mock模式,需要对Mock对象的方法进行模拟。这个分为两类:Spock和PowerMock(结合Mockito)。原因是在混合静态资源和非静态资源场景下,指定了PowerMock的@RunWith运行规则,不兼容Spock写法,需要用到PowerMock框架Mock对象的功能。

三、Mock被测对象

1.@Autowired构造方法

用一个controller举例,源代码如下:

@Api(tags = "SLA规则管理模块")

@Slf4j

@RestController

@RequestMapping("/hickwall/v1/static/sla")

public class FunController {

HttpServletRequest request;

ISlaService service;

@Autowired

public FunController(HttpServletRequest request, ISlaService service) {

this.request = request;

this.service = service;

}

}

Spock单测代码如下:

import com.funtester.service.ISlaService

import com.funtester.vo.sla.SlaBean

import spock.lang.Shared

importhttp:// spock.lang.Specification

import javax.servlet.http.HttpServletRequest

class FunControllerTest extends Specification {

def service = Mock(ISlaService)

@Shared

def request = Mock(HttpServletRequest)

def FunController = new FunController(request, service)

}

2.@Autowired属性对象,无构造方法

源代码如下:

public class ApiImpl implements IApi {

@Autowired

private ApiRMapper mapper;

}

Spock单测部分代码如下:

import com.funtester.mapper.ApiRMapper

import com.funtester.vo.ApiR

import spock.lang.Shared

import spock.lang.Specification

ApiRMapper mapper = Mock(ApiRMapper)

def drive = new ApiImpl(mapper:mapper)

3.PowerMock用法

场景也分为两种:有无构造方法,除了Mock方法不同以外,其他均相同,这里不列举。

PS:如果对象属性中有未被@Autowired注释的属性,不能用@AllArgsConstructor的lombok注解,服务启动会报错。

源代码如下:

@Component

@Slf4j

public class TaskScheduled {

@Autowired

IService service;

@Value("${hickwall.statistic.cid}")

public String cid;

}

4.共享对象以及初始化

统一使用Spock提供的功能,用到的注解@Shared,不加的话无法在Spock方法中进行赋值操作,但是可以当做一个普通的对象使用。

Spock框架Demo:

@Shared

def slaBean = new SlaBean()

def setupSpec() {

request.getHeader("operator") >> "FunTester"

slaBean.name = "测试"

slaBean.quota = 1

slaBean.upstream = "PRO"

slaBean.threshold = 0.1

slaBean.crWGrjGNHdeator = "FunTester"

slaBean.id = 100

}

四、定义对象行为

1.Spock定义Mock对象行为

基础的Spock语法结构when-then-expct如下:

def "AddSla"() {

when:

def sla = FunController.addSla(slaBean)

then:

service.addSla(_) >> {f ->

assert "FunTester" in f.creator

1

}

expect:

sla.code == 0

sla.data == 1

}

也可以在最开始加上given,when和then通常一起使用。

上述Demo在Mock方法的时候对参数进行了断言和处理,这也是Spock框架的一个特性,其他均为Groovy语法特性。

其他定义Mock行为的语法如下:

service.getAllGroup(_,_) >> null//返回null

service.getAllGroup(_,_) >> {throw new Exception()} //抛出异常

service.getAllGroup(_,_) >> []//返回空list,Groovy默认实现ArrayList

service.getAllGroup(_,_) >> [slaBean,slaBean]//返回正常list

service.getAllGroup(_,_) >> [slaBean,slaBean]//返回正常list

service.getAllGroup(_,10) >> [slaBean,slaBean]//定时某个参数

service.getAllGroup(any(),10) >> [slaBean,slaBean]//any()等效于_

service.getAllGroup(any(),10) >> service.getAllGroup(1,10)//调用其他方法返回

2.Mockito模拟对象行为

Mockito和PowerMock配合使用语法稍微复杂一些。首先我们需要先定义对象行为(通常在com.funtesterbase.task.TaskScheduledTest#setupSpec方法中),然后在用例用使用。

定时对象行为:

Mockito.when(newutil.filter(Mockito.any())).thenReturn(true)

定义行为以后,就可以在Spock用例中正常使用,包括在通过Mock对象创建的对象方法中,如果调用到定义过行为的方法,也会走自定义的逻辑。

其他常用定义行为:

Mockito.when(newutil.filter(Mockito.any())).thenReturn(null)

Mockito.when(newutil.filter(Mockito.any())).thenThrow(Exception.class)//抛出异常

PowerMockito.doNothing().when(newutil).filter(Mockito.any(ArrayList.class))//dothing,什么都不做

第三个例子中我们假设filter方法是一个无返回的void方法。

通常我们需要构建返回对象,如果对象需要赋值的属性过多,可以使用初始化赋值的方法,下面是Mock一个返回list的方法返回值的Demo:

Mockito.when(newser.selectAllService()).thenReturn([new NewInterface() {

{

setUrl("/abc")

setNname("test TGFC z;/./")

setMethod("GET")

}

}, new NewInterface() {

{

setUrl("/abcd")

setNname("test")

setMethod("POST")

}

}, new NewInterface() {

{

setUrl(http://"/abce")

setNname("test")

setMethod("GET")

}

}])


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Python 正则表达式(高级用法)- search、findall、sub 、split
下一篇:Python采用并发查询mysql以及调用API灌数据 (八)- 异步并发加锁,保证数据安全...(python并发写入mysql)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~