Spring 初探(十一)(Test REST Service)
2017-01-03 20:39
288 查看
下面对于Test REST Service展开介绍
用到的不太熟悉的函数:
org.junit.Before
在进行一些test之前 后续可能用到一些类似的对象 对于public method施加@Before
使得method在@Test method之前运行
当对于标记了@Before的类进行派生时,派生类@Before函数在基类之后运行。
org.junit.Test
执行Test 的public method 在test 中抛出的异常 将会由JUnit报告为failure
要对RunWith有一个结构上的理解 需要对一些基本概念进行介绍
Junit 提供了tools来进行套件(suite)的运行及结果展示
运行tests 并在console中看结果 需要运行如下代码:
Ex:
或者:
在test class中添加如下静态代码:
Ex:
上述方法的运行是通过test runner进行的。
junit.textui.TestRunner
这是一个通过命令行运行test的工具类。
其以TestCase的名称为参数进行运行。
调用进行运行的方法除了在命令行外 还可以调用runner的与run相关的方法,
如上面的runClasses方法
Spring 提供的SpringJUnit4ClassRunner与常用的Suite
都作为自定义runner 当需要使用这些runners时需要在相应的Test class
前面加@RunWith annotation 并制定使用的runner名称。
其它第三方runner及关于runner的简要介绍参见:
https://github.com/junit-team/junit4/wiki/Test-runners
比较详尽的介绍参见:
http://www.mscharhag.com/java/understanding-junits-runner-architecture
org.springframework.boot.test.SpringApplicationConfiguration
类一级别的annotation 可以用来指定初始化的ApplicationContext
用于将相应的应用环境导入到测试类中。
org.springframework.http.MediaType
可以完成关于传输内容的描述。(如格式及编码)
具体使用方法见下例
org.springframework.http.HttpMessageConverter(接口)
converter from and to HTTP requests and responses
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
上述HttpMassageConverter的实现 并且可以读写json (使用ObjectMapper进行转换)
其一般支持的数据形式设定为application/json and application/*+json with UTF-8 character set
前面的数据格式及后面的字符集格式可以由前述MediaType进行描述。(见下例)
org.springframework.mock.http.MockHttpOutputMessage
HttpOutputMessage 的mock 实现(用于测试的虚拟实现)
HttpOutputMessage 仅仅是提供getBody的接口 一般被Http request在客户端实现
或者response在服务端实现。
其代码见:
https://github.com/spring-projects/spring-test-mvc/blob/master/src/main/java/org/springframework/mock/http/MockHttpOutputMessage.java
仅仅是实现测试功能。
org.springframework.test.context.junit4.SpringJunit4ClassRunner
将要在下面使用的junit runner class
使用不同runner class的一个原因是其给出的不同annotations
org.springframework.test.context.web.WebAppConfiguration
class水平annotation 设定被test环境实现的ApplicationContext(应用配置的核心接口)
应该为WebApplicationContext
ApplicationContext的基本使用在前面已经做了例证
如
Spring 初探(五)中的ConfigurableApplicationContext就作为
其一个派生接口
一般的如在手动配置xml 调用getBean时使用ApplicationContext进行相应操作
如增加(自定义)ApplicationListener 时(调用addApplicationListener)
时使用ConfigurableApplicationContext进行调用
下面即将要提到的WebApplicationContext相对于ApplicationContext的特点
是提供getServletContext method (其返回标准 Servlet API ServletContext)
ServletContext 定义了Servlet与Servlet Container交互的方法。
org.springframework.test.web.servlet.MockMVC
对于服务端Spring MVC test的 main入口
有了这个entry 发送url请求及其检测(RequestMatcher)变得容易
(提供一整套内置方法)
org.springframework.web.context.WebApplicationContext
在 org.springframework.test.context.web.WebAppConfiguration已经介绍
这里还使用了部分静态导入的形式
使用通配符将导入相应类的所有静态方法
org.hamcrest.Matchers.*
提供了若干个测试描述的方法 这里所使用的是常用的
is(a thin wrapper for equalTo(value))
Hamcrest的功能进本上就是测试(assert assertEquals assertThat)
其相关的简要介绍见:
http://www.vogella.com/tutorials/Hamcrest/article.html#hamcrestoverview
org.junit.Assert
这里使用AssertNotNull
下面的三个类给出了测试具体使用到的静态方法。
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
发送请求的get post等方法为该类静态方法
org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
其定义了如jsonPath(String expression, org.hamcrest.Matcher<T> matcher)
这种根据expression找到相应的json部分并使用Matcher进行比较的方法
其中的expression 为JSONPath expression
其设计是要有一种类似于Xpath解析xml结构的解析json数据的方法
相应介绍见:
http://goessner.net/articles/JsonPath/
可以参看xpath 与json的符号对照表来看。
org.springframework.test.web.servlet.setup.MockBuilders
这里使用了其定义的函数 webAppContextSetup进行
webApplicationContext 的应用环境设定。
下面给出使用到的例子及其构建的过程描述:
Ex:
下面对上述构建过程进行描述:
对类进行RunWith指定测试runner
在初始化 contextType的过程中 需要指定主类型及子类型
这里使用了相应名称的函数 所谓主类型 子类型来源于 MINE媒体类型的区分
实际上 MediaType是作为MineType的派生类 所以具有相应初始化格式
一般在http传输中 有关额设定作为传输的参数进行设定
在下面一个小页面给出了一些简单列举:
http://www.cnblogs.com/wuzy/archive/2013/06/04/3118012.html 这个页面的http request headers 的相应属性为:
Content-Type:text/html; charset=utf-8
(chorme)
/前为主属性 后为子属性
在我们例子中需要的是 application/json; charset=utf-8
在前面已经对于Spring @Autowired 进行叙述
这里要补充的是 当对于进行@Autowired修饰的方法 如setter construct等方法
其参数为Collection or Map dependency type时
the container will autowired all beans matching the declared value type
这里对于setConverters的处理正是使用了此特性。
注意HttpMessageConverter<T> 就是使用T作为格式转换的类型
而 MappingJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object>
是实现java对象与message的转换
stream 的findAny方法返回一个Optional<T>对象
当stream不为空时返回包含的stream的某个Optional 否则为empty Optional
这里可能由于不在乎find的顺序使用并行stream比findFirst快。
相应介绍见:
http://stackoverflow.com/questions/25912185/java-8-stream-findany-vs-finding-a-random-element-in-the-stream
setup
JpaRepository.deleteAllInBatch()
delete all entities in a batch call
json
此函数完成object向 json形式String的转换 所用的类及相应方法已经在上面
提及。
userNotFound
MockMvcRequestBuilders 静态方法post 生成MockHttpServletRequestBuilder
对于此builder 调用content (这里是String参数)可以设定 request body
perform会返回ResultActions对象 可以执行检测
andExpect perform an expectation
MockMvcResultMatcher status() 进行 response status assertions
其isNotFound() assert response status code HttpStatus.NOT_FOUND
这与输入的 userId george 是并不存在的是相对应的。
到此为止已经多次用到builder函数 之前是 ServletUriComponentsBuilder
builder的常见形式是其方法作为对于build对象的加工返回builder本身。
readSingleBookmark
使用的get status content等与userNotFound类似
所使用的JSONPath是简单的。
readBookmarks
org.hamcrest.Matchers hasSize是对应collection调用size()的相应
assertion
剩余的部分是易于理解的。
如果想进一步了解细节,可参看原文链接: http://spring.io/guides/tutorials/bookmarks/
用到的不太熟悉的函数:
org.junit.Before
在进行一些test之前 后续可能用到一些类似的对象 对于public method施加@Before
使得method在@Test method之前运行
当对于标记了@Before的类进行派生时,派生类@Before函数在基类之后运行。
org.junit.Test
执行Test 的public method 在test 中抛出的异常 将会由JUnit报告为failure
要对RunWith有一个结构上的理解 需要对一些基本概念进行介绍
Junit 提供了tools来进行套件(suite)的运行及结果展示
运行tests 并在console中看结果 需要运行如下代码:
Ex:
org.junit.runner.JUnitCore.runClasses(TestClass1.class,...)
或者:
在test class中添加如下静态代码:
Ex:
public static Test suite(){ return new JUnit4TestAdapter("YourJUnit4TestClass".class); }
上述方法的运行是通过test runner进行的。
junit.textui.TestRunner
这是一个通过命令行运行test的工具类。
其以TestCase的名称为参数进行运行。
调用进行运行的方法除了在命令行外 还可以调用runner的与run相关的方法,
如上面的runClasses方法
Spring 提供的SpringJUnit4ClassRunner与常用的Suite
都作为自定义runner 当需要使用这些runners时需要在相应的Test class
前面加@RunWith annotation 并制定使用的runner名称。
其它第三方runner及关于runner的简要介绍参见:
https://github.com/junit-team/junit4/wiki/Test-runners
比较详尽的介绍参见:
http://www.mscharhag.com/java/understanding-junits-runner-architecture
org.springframework.boot.test.SpringApplicationConfiguration
类一级别的annotation 可以用来指定初始化的ApplicationContext
用于将相应的应用环境导入到测试类中。
org.springframework.http.MediaType
可以完成关于传输内容的描述。(如格式及编码)
具体使用方法见下例
org.springframework.http.HttpMessageConverter(接口)
converter from and to HTTP requests and responses
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
上述HttpMassageConverter的实现 并且可以读写json (使用ObjectMapper进行转换)
其一般支持的数据形式设定为application/json and application/*+json with UTF-8 character set
前面的数据格式及后面的字符集格式可以由前述MediaType进行描述。(见下例)
org.springframework.mock.http.MockHttpOutputMessage
HttpOutputMessage 的mock 实现(用于测试的虚拟实现)
HttpOutputMessage 仅仅是提供getBody的接口 一般被Http request在客户端实现
或者response在服务端实现。
其代码见:
https://github.com/spring-projects/spring-test-mvc/blob/master/src/main/java/org/springframework/mock/http/MockHttpOutputMessage.java
仅仅是实现测试功能。
org.springframework.test.context.junit4.SpringJunit4ClassRunner
将要在下面使用的junit runner class
使用不同runner class的一个原因是其给出的不同annotations
org.springframework.test.context.web.WebAppConfiguration
class水平annotation 设定被test环境实现的ApplicationContext(应用配置的核心接口)
应该为WebApplicationContext
ApplicationContext的基本使用在前面已经做了例证
如
Spring 初探(五)中的ConfigurableApplicationContext就作为
其一个派生接口
一般的如在手动配置xml 调用getBean时使用ApplicationContext进行相应操作
如增加(自定义)ApplicationListener 时(调用addApplicationListener)
时使用ConfigurableApplicationContext进行调用
下面即将要提到的WebApplicationContext相对于ApplicationContext的特点
是提供getServletContext method (其返回标准 Servlet API ServletContext)
ServletContext 定义了Servlet与Servlet Container交互的方法。
org.springframework.test.web.servlet.MockMVC
对于服务端Spring MVC test的 main入口
有了这个entry 发送url请求及其检测(RequestMatcher)变得容易
(提供一整套内置方法)
org.springframework.web.context.WebApplicationContext
在 org.springframework.test.context.web.WebAppConfiguration已经介绍
这里还使用了部分静态导入的形式
使用通配符将导入相应类的所有静态方法
org.hamcrest.Matchers.*
提供了若干个测试描述的方法 这里所使用的是常用的
is(a thin wrapper for equalTo(value))
Hamcrest的功能进本上就是测试(assert assertEquals assertThat)
其相关的简要介绍见:
http://www.vogella.com/tutorials/Hamcrest/article.html#hamcrestoverview
org.junit.Assert
这里使用AssertNotNull
下面的三个类给出了测试具体使用到的静态方法。
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
发送请求的get post等方法为该类静态方法
org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
其定义了如jsonPath(String expression, org.hamcrest.Matcher<T> matcher)
这种根据expression找到相应的json部分并使用Matcher进行比较的方法
其中的expression 为JSONPath expression
其设计是要有一种类似于Xpath解析xml结构的解析json数据的方法
相应介绍见:
http://goessner.net/articles/JsonPath/
可以参看xpath 与json的符号对照表来看。
org.springframework.test.web.servlet.setup.MockBuilders
这里使用了其定义的函数 webAppContextSetup进行
webApplicationContext 的应用环境设定。
下面给出使用到的例子及其构建的过程描述:
Ex:
package bookmarks; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.mock.http.MockHttpOutputMessage; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.context.WebApplicationContext; import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*; /** * Created by admin on 2017/1/3. */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebAppConfiguration public class BookmarkRestControllerTest { private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8")); private MockMvc mockMvc; private String userName = "bdussault"; private HttpMessageConverter mappingJackson2HttpMessageConverter; private Account account; private List<Bookmark> bookmarkList = new ArrayList<>(); @Autowired private BookmarkRepository bookmarkRepository; @Autowired private WebApplicationContext webApplicationContext; @Autowired private AccountRepository accountRepository; @Autowired void setConverters(HttpMessageConverter<?>[] converters){ this.mappingJackson2HttpMessageConverter = Arrays.asList(converters).stream().filter(hmc -> hmc instanceof MappingJackson2HttpMessageConverter) .findAny().orElse(null); asser d24e tNotNull("the JSON message converter must not be null", this.mappingJackson2HttpMessageConverter); } @Before public void setup(){ this.mockMvc = webAppContextSetup(webApplicationContext).build(); this.bookmarkRepository.deleteAllInBatch(); this.accountRepository.deleteAllInBatch(); this.account = accountRepository.save(new Account(userName, "password")); this.bookmarkList.add(bookmarkRepository.save(new Bookmark(account, "http://bookmark.com/1/" + userName, "A description"))); this.bookmarkList.add(bookmarkRepository.save(new Bookmark(account, "http://bookmark.com/2/" + userName, "A description"))); } @Test public void userNotFound() throws Exception { mockMvc.perform(post("/george/bookmarks/").content(this.json(new Bookmark())). contentType(contentType)).andExpect(status().isNotFound()); } @Test public void readSingleBookmark() throws Exception{ mockMvc.perform(get("/" + userName + "/bookmarks/" + this.bookmarkList.get(0).getId())) .andExpect(status().isOk()) .andExpect(content().contentType(contentType)) .andExpect(jsonPath("$.id", is(this.bookmarkList.get(0).getId().intValue()))) .andExpect(jsonPath("$.uri", is("http://bookmark.com/1/" + userName))) .andExpect(jsonPath("$.description", is("A description"))); } @Test public void readBookmarks() throws Exception { mockMvc.perform(get("/" + userName + "/bookmarks")) .andExpect(status().isOk()) .andExpect(content().contentType(contentType)) .andExpect(jsonPath("$", hasSize(2))) .andExpect(jsonPath("$[0].id", is(this.bookmarkList.get(0).getId().intValue()))) .andExpect(jsonPath("$[0].uri", is("http://bookmark.com/1/" + userName))) .andExpect(jsonPath("$[0].description", is("A description"))) .andExpect(jsonPath("$[1].id", is(this.bookmarkList.get(1).getId().intValue()))) .andExpect(jsonPath("$[1].uri", is("http://bookmark.com/2/" + userName))) .andExpect(jsonPath("$[1].description", is("A description"))); } @Test public void createBookmark() throws Exception { String bookmarkJson = json(new Bookmark( this.account, "http://spring.io", "a bookmark to the best resource for Spring news and information")); this.mockMvc.perform(post("/" + userName + "/bookmarks") .contentType(contentType) .content(bookmarkJson)) .andExpect(status().isCreated()); } protected String json(Object o)throws IOException{ MockHttpOutputMessage mockHttpOutputMessage = new MockHttpOutputMessage(); this.mappingJackson2HttpMessageConverter.write(o, MediaType.APPLICATION_JSON, mockHttpOutputMessage); return mockHttpOutputMessage.getBodyAsString(); } }
下面对上述构建过程进行描述:
对类进行RunWith指定测试runner
在初始化 contextType的过程中 需要指定主类型及子类型
这里使用了相应名称的函数 所谓主类型 子类型来源于 MINE媒体类型的区分
实际上 MediaType是作为MineType的派生类 所以具有相应初始化格式
一般在http传输中 有关额设定作为传输的参数进行设定
在下面一个小页面给出了一些简单列举:
http://www.cnblogs.com/wuzy/archive/2013/06/04/3118012.html 这个页面的http request headers 的相应属性为:
Content-Type:text/html; charset=utf-8
(chorme)
/前为主属性 后为子属性
在我们例子中需要的是 application/json; charset=utf-8
在前面已经对于Spring @Autowired 进行叙述
这里要补充的是 当对于进行@Autowired修饰的方法 如setter construct等方法
其参数为Collection or Map dependency type时
the container will autowired all beans matching the declared value type
这里对于setConverters的处理正是使用了此特性。
注意HttpMessageConverter<T> 就是使用T作为格式转换的类型
而 MappingJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object>
是实现java对象与message的转换
stream 的findAny方法返回一个Optional<T>对象
当stream不为空时返回包含的stream的某个Optional 否则为empty Optional
这里可能由于不在乎find的顺序使用并行stream比findFirst快。
相应介绍见:
http://stackoverflow.com/questions/25912185/java-8-stream-findany-vs-finding-a-random-element-in-the-stream
setup
JpaRepository.deleteAllInBatch()
delete all entities in a batch call
json
此函数完成object向 json形式String的转换 所用的类及相应方法已经在上面
提及。
userNotFound
MockMvcRequestBuilders 静态方法post 生成MockHttpServletRequestBuilder
对于此builder 调用content (这里是String参数)可以设定 request body
perform会返回ResultActions对象 可以执行检测
andExpect perform an expectation
MockMvcResultMatcher status() 进行 response status assertions
其isNotFound() assert response status code HttpStatus.NOT_FOUND
这与输入的 userId george 是并不存在的是相对应的。
到此为止已经多次用到builder函数 之前是 ServletUriComponentsBuilder
builder的常见形式是其方法作为对于build对象的加工返回builder本身。
readSingleBookmark
使用的get status content等与userNotFound类似
所使用的JSONPath是简单的。
readBookmarks
org.hamcrest.Matchers hasSize是对应collection调用size()的相应
assertion
剩余的部分是易于理解的。
如果想进一步了解细节,可参看原文链接: http://spring.io/guides/tutorials/bookmarks/
相关文章推荐
- Spring 初探(十二)(HATEOAS REST Service)
- spring mvc rest webservice 在jboss 下 406 错误的解决方法
- Java源码 SpringMVC Mybatis Shiro Bootstrap Rest Webservice
- 梦想Spring-MVC,Restful,GWT,RestWebService
- SpringBoot系列十一:SpringBoot整合Restful架构(使用 RestTemplate 模版实现 Rest 服务调用、Swagger 集成、动态修改日志级别)
- cxf 3.2+webservice+spring 4.2发布Rest WebService
- Java源码 SpringMVC Mybatis Shiro Bootstrap Rest Webservice
- spring-guide之rest-service
- Spring Rest Docs WebTestClient自动生成接口文档Gradle版
- spring扫描出现Annotation-specified bean name 'userService' for bean class [com.test.service.UserService]
- rest service + spring boot + docker - (a != b) ? b : a - ITeye技术网站
- Spring中控制反转怎么配置的?比如Action类有个成员变量TestService testService,Action类就可以直接用TestServiceIMP中的方法了
- Spring Boot Rest Service 下载文件
- spring-boot-mybatis-rest-service-demo
- Spring 4 MVC @RestController 注解实现REST Service(带源码)
- Spring Boot Rest Service 下载文件
- How to test Service Layer in Spring web app
- Java源码 SpringMVC Mybatis Shiro Bootstrap Rest Webservice
- org.springframework.expression.spel.SpelEvaluationException: EL1004E: Method call: Method service() cannot be found on com.my.blog.springboot.thymeleaf.util.MethodTest type
- spring mvc restfull webservice