Spring boot的基础总结(七)-------Mock和restassured的合体

一.序
最近在搞Spring boot的接口测试的问题,为了保证代码的质量和功能实现,想想好像只有Junit可以帮我搞一搞。但是很多问题接踵而至。

我的服务和其它服务有关联(有点像微服务),那在脱离了其它服务依赖的时候,我该如何进行测试?

那么神奇的我找了很多资料,总算总结了以下两个可执行的东西。
(一)Mock可以对数据进行打桩,模拟对象返回
(二)restassured可以简化 HTTP Builder 顶层 ,验证REST服务
本身rest-assured是没办法进行数据打桩的,所以要搭配Mock在一起。
而Mock本身也是不跟rest-assured有什么关联。但是!!!rest-assured将MockMVC集合在一起了,所以两个的配合得到了一定保证。

二.Mock
mock就是创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象
可以解决以下两个问题:

1.验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等
2.指定这个对象的某些方法的行为,返回特定的值,或者是执行特定的动作

而Mock,我们经常使用的就是Mockito里面的东西。
在Springboot中,我们增加依赖

      <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.mockito/mockito-all --><dependency><groupId>org.mockito</groupId><artifactId>mockito-all</artifactId><version>1.10.19</version><scope>test</scope></dependency>

创建TestControl,并构造hello方法

public class TestController {@RequestMapping("/hello")@ResponseBodypublic String hello() {return "user";}
}

在JunitTest类中引入静态资源

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

然后我们来使用mockito进行测试。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class TestControllerTest {@MockBeanTestController testController;@Testvoid hello() throws RetException {//.当调用control中的he方法,则返回我们指定的值。。Mockito.when(testController.he()).thenReturn("ReTurnValue");//执行后,可以发现,本身返回"user"的方法,现在返回"ReTurnValue"System.out.println(testController.he());}
}

这里只介绍最简单的用法,总结一个Mockito就是模仿你本身的对象,并且返回你自己“设定”的返回值。可以看到,Mockito的职能并不包含去测试Controller层
更多的mockito使用方法
不过为了更好理解下面的合体,这里还要在多介绍一些注解。
可以看到Mock对象是加了@MockBean注解的。
这里可以看大佬写的

@McokBean:是将模拟对象添加到Spring应用程序上下文中,这个模拟会替换上下文里面任何相同类型 Control层里面有Service.此时,模拟Service.
@Mock:Mock声明的对象,对函数的调用均执行mock(即虚假函数),不执行真正部分。
@Spy:声明的对象,对函数的调用均执行真正部分。保留真实对象,除非你设定了确定的返回,否则按照真实的走。
@InjectMock:InjectMock声明的对象,创建该类的实例,并将使用@Mock注解创建的模拟注入该实例(不懂的看到后面合体就知道了)
可以说其余用@Mock注解创建的mock就会注入到这个实例里面。。

MockBean和Mock的区别:MockBean会替代所有 上下文中所有相同类型的Mock.Mock只是模拟对象。
Mock和Spy的区别:Mock模拟的对象里面的方法,如果没有设备返回,那么都是返回null,spy的话如果没有设定其中的方法,那么走的就是真实对象里的方法。
Mock和InJectMock的区别:Controller层里面要调用Service层,那我Mock的是Service层的接口,那我去调用Controller层的时候,这个Mock的Service就要通过这个方式注入。

三.rest-assured
Rest-Assured是一个REStfulApi测试的利器,可以很方便的去测试自己的API。主要就是调用你自己Controller层来完成自己的测试。当然,它属于一个框架,如果你不喜欢用它,直接用MockMVC也是可以的,那你不继续往下看也是可以的。
我们先来看最基础的调用。
添加依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--做测试用的--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency><!--做测试用的--><dependency><groupId>io.rest-assured</groupId><artifactId>rest-assured</artifactId><version>3.3.0</version><scope>test</scope></dependency>

在JunitTest类中,添加静态依赖

io.restassured.RestAssured.*
io.restassured.matcher.RestAssuredMatchers.*
org.hamcrest.Matchers.*

这里也加上了json数据的使用方法.

 @Testvoid userMessage() {Base_User_R x = new Base_User_R();x.setA("a");x.setO("o");//这里将模拟http请求发送json数据到APi接口given().contentType("application/json").body(x).log().all().when().post("http://localhost:8088/Get/User/Message").//输出到接口then().assertThat().body("data.age", equalTo(18)).//断言判断返回的json中data:{age:""}是否等于18assertThat().body("data.name", equalTo("louki")).assertThat().body("code",equalTo(200));}

这里只做实例,其它方法就暂时先不放出来。执行后,根据log,可以看到方法执行的是否正常。

四.restassuredMvc和Mock

最重要的来了!!!
这是我们的Controller层

   public class TestController{//路径映射,对应浏览器访问的地址,访问该路径则执行下面函数@RequestMapping("/hello1")@ResponseBodypublic String hello1() {return gTestServer.he();}

这是Service层

public class TestServer {public String he(){return "hehehehee";}}

如果你直接使用rest-assured,然后使用Mock去模拟了一个方法的返回。我一开始认为,这样是没什么问题的,毕竟。我Mock了Service中的调用。但是显而易见,悲剧是一定会发生的。

   @MockBeanTestServer testServer;void userMessage2() throws RetException {Base_User_R x = new Base_User_R();x.setA("a");x.setO("o");x.setUseraccount("louki_test");//这个是隔离服务的.当调用control的这个方法且,x为这样的时候,返回。。Mockito.when(testServer.he()).thenReturn("ReTurnValue");System.out.println(testServer.he());RestAssured.given().contentType("application/json").body(x).log().all().when().post("/hello1").then().log().all().assertThat().body(containsString("ReTurnValue"));}

根据log可以看出,在调用Service.he方法时,确实已经根据我们设置的返回,返回的是"ReTurnValue"。但是在Rest-Assured却没有调用Mock中的方法
在这里插入图片描述
在这里插入图片描述
后面我看到,Mockito一般是搭配着MockMVC去做Api的测试,那Rest-Assured里面也是继承了MockMVC的,那我就开始尝试Rest_AssuredMVC去搭配MockMVC的去使用。
依赖不变,Controller,Service层不变。
我们改变使用的是RestAssuredMockMvc中given方法.

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class Get_UserControlTest {@MockBeanTestServer testServer;//这两个注解很重要,如果不加,也是造成同样的结果.//Autowired不加,则造成空指针@InjectMocks@AutowiredTestController xxx;@Testvoid userMessage() throws RetException {Base_User_R x = new Base_User_R();x.setA("a");x.setO("o");x.setUseraccount("louki_test");//这个是隔离服务的.当调用control的这个方法且,x为这样的时候,返回。。Mockito.when(testServer.he()).thenReturn("ReTurnValue");System.out.println(testServer.he());RestAssuredMockMvc.given().standaloneSetup(xxx).contentType("application/json").body(x).log().all().when().post("/hello1").then().log().all().assertThat().body(containsString("ReTurnValue"));}}

运行结果,皆大欢喜。
在这里插入图片描述
这里需要注意的是,Control层需要用@InjectMocks进行注解。而我们模拟Mock的Service层需要用@Mock注解。这样就把我们模拟的Mock注入到我们调用的Restassured中
这中间真的尝试了很多方法,有好多坑。而且我发现没有放在一起用的,只能靠自己一步一步摸索,在此记录一下,如果对你有用的,可以点一个小小赞~谢谢。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部