文档章节

spring boot 测试

文小杰
 文小杰
发布于 2017/09/08 13:42
字数 1599
阅读 19
收藏 0

spring boot 集成测试

一、集成测试自动配置

代码清单4-1 用SpringJUnit4ClassRunner对Spring应用程序进行集成测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
classes=AddressBookConfiguration.class)                   //加载应用程序上下文
    public class AddressServiceTests {
@Autowired
    private AddressService addressService;                //注入地址服务
@Test                                                     
    public void testService() {                           //测试地址服务
        Address address = addressService.findByLastName("Sheman");
        assertEquals("P", address.getFirstName());
        assertEquals("Sherman", address.getLastName());
        assertEquals("42 Wallaby Way", address.getAddressLine1());
        assertEquals("Sydney", address.getCity());
        assertEquals("New South Wales", address.getState());
        assertEquals("2000", address.getPostCode());
}
}

解释:

  1. SpringJUnit4ClassRunner:是一个JUnit类运行器,会为JUnit测试加载Spring应用程 序上下文,并为测试类自动织入所需的Bean。
  2. 可以把@ContextConfiguration替换为Spring Boot的@SpringApplicationConfiguration, 这样不仅会加载应用程序上下文,还会开启日志、加载外部属性(application.properties或application.yml),以及其他Spring Boot特性。 大多数情况下,为Spring Boot应用程序编写测试时应该用@SpringApplicationConfiguration代替@ContextConfiguration。

二、测试Web应用程序

要恰当地测试一个Web应用程序,需要投入一些实际的HTTP请求,确认它能正确地处理 那些请求。Spring Boot开发者有两个可选的方案能实现这类测试:

  • Spring Mock MVC:能在一个近似真实的模拟Servlet容器里测试控制器,而不用实际启动 应用服务器。
  • Web集成测试:在嵌入式Servlet容器(比如Tomcat或Jetty)里启动应用程序,在真正的应 用服务器里执行测试。

1. 模拟Spring MVC

要在测试里设置Mock MVC,可以使用MockMvcBuilders,该类提供了两个静态方法:

  • standaloneSetup():构建一个Mock MVC,提供一个或多个手工创建并配置的控制器。
  • webAppContextSetup():使用Spring应用程序上下文来构建Mock MVC,该上下文里 可以包含一个或多个配置好的控制器。

两个方法区别:

  • standaloneSetup():手工初始化并注入要测试的控制器,
  • webAppContextSetup():基于一个WebApplicationContext的实例,通常由Spring加载。

前者同单元测试更加接近,你可能只想让它专注于单一控制器的测试,而后者让Spring加载控制 器及其依赖,以便进行完整的集成测试。

/* 代码清单4-2 为集成测试控制器创建Mock MVC */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(
classes = ReadingListApplication.class)         //开启Web上下文
@WebAppConfiguration
    public class MockMvcWebTests {
    @Autowired
    private WebApplicationContext webContext;   //注入WebApplicationContext
    private MockMvc mockMvc;
    @Before
    public void setupMockMvc() {
        mockMvc = MockMvcBuilders
        .webAppContextSetup(webContext)        //设置MockMvc
        .build();
    }
}
/* 向/readingList发起一个GET请求 */
@Test
public void homePage() throws Exception {
    mockMvc.perform(get("/readingList"))
        .andExpect(status().isOk())
        .andExpect(view().name("readingList"))
        .andExpect(model().attributeExists("books"))
        .andExpect(model().attribute("books", is(empty())));
}
/* 向/readingList发起一个POST请求 */
@Test
public void postBook() throws Exception {
    mockMvc.perform(post("/readingList")
        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
        .param("title", "BOOK TITLE")
        .param("author", "BOOK AUTHOR")
        .param("isbn", "1234567890")
        .param("description", "DESCRIPTION"))
        .andExpect(status().is3xxRedirection())
        .andExpect(header().string("Location", "/readingList"));
/* 验证刚刚的POST请求 */
//配置期望的图书
Book expectedBook = new Book();   
expectedBook.setId(1L);
expectedBook.setReader("craig");
expectedBook.setTitle("BOOK TITLE");
expectedBook.setAuthor("BOOK AUTHOR");
expectedBook.setIsbn("1234567890");
expectedBook.setDescription("DESCRIPTION");
//执行GET请求
mockMvc.perform(get("/readingList"))
    .andExpect(status().isOk())
    .andExpect(view().name("readingList"))
    .andExpect(model().attributeExists("books"))
    .andExpect(model().attribute("books", hasSize(1)))
    .andExpect(model().attribute("books",
    contains(samePropertyValuesAs(expectedBook))));
}

2. 测试Web安全

使用Spring Security

  1. 添加依赖

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <scope>test</scope>
    </dependency>
    
  2. 在创建MockMvc实例时运用Spring Security的配置器

    @Before
    public void setupMockMvc() {
        mockMvc = MockMvcBuilders
        .webAppContextSetup(webContext)
        .apply(springSecurity())
        .build();
    }
    
  3. 使用(具体的安全配置取决于你如何配置Spring Security(或者Spring Boot如何自动配置Spring Security)。)

    场景代码:

    1)请求未经身份验证

    /* 请求未经身份验证,重定向回登录界面 */
    @Test
    public void homePage_unauthenticatedUser() throws Exception {
        mockMvc.perform(get("/"))
        .andExpect(status().is3xxRedirection())
        .andExpect(header().string("Location",
        "http://localhost/login"));
    }
    

    2)请求经过身份验证 Spring Security提供了两个注解:

    • @WithMockUser:用给定的值创建了一个UserDetails对象,指定用户名、密码和授权。
    • @WithUserDetails:使用事先配置好的UserDetailsService来加载UserDetails对象,根据给定的用户名查找 并返回一个Reader对象。
    /* 经过身份验证的请求,使用@WithMockUser */
    @Test
    @WithMockUser(username="craig",
       password="password",
       roles="READER")
       public void homePage_authenticatedUser() throws Exception {
       ...
    }
    
    /* 经过身份验证的请求,使用@WithUserDetails */
    @Test
    @WithUserDetails("craig")
    public void homePage_authenticatedUser() throws Exception {
       Reader expectedReader = new Reader();
       expectedReader.setUsername("craig");
       expectedReader.setPassword("password");
       expectedReader.setFullname("Craig Walls");
       mockMvc.perform(get("/"))
           .andExpect(status().isOk())
           .andExpect(view().name("readingList"))
           .andExpect(model().attribute("reader",
           samePropertyValuesAs(expectedReader)))
           .andExpect(model().attribute("books", hasSize(0)))
    }
    

    此处没有启动Servlet容器来运行这些测试, Spring的Mock MVC取代了实际的Servlet 容器。它比直接调用控制器方法要好,但它并没有真的在Web浏 览器里执行应用程序,验证呈现出的视图。

三、测试运行中的应用程序

Spring Boot支持用嵌入式Servlet容器来启动应用程序。

Spring Boot 的 @WebIntegrationTest 注解就是这么做的。 在测试类上添加@WebIntegrationTest注解,可以声明你不仅希望Spring Boot为测试创建应用程序上下文,还要启 动一个嵌入式的Servlet容器。一旦应用程序运行在嵌入式容器里,你就可以发起真实的HTTP请 求,断言结果了。

/* 代码清单4-5 在服务器里启动应用程序,以Spring的RestTemplate对应用程序发起HTTP请求 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(
classes=ReadingListApplication.class)
@WebIntegrationTest
public class SimpleWebTest {
    @Test(expected=HttpClientErrorException.class)
    public void pageNotFound() {
        try {
        RestTemplate rest = new RestTemplate();
        rest.getForObject(
            "http://localhost:8080/bogusPage", String.class);
        fail("Should result in HTTP 404");
        } catch (HttpClientErrorException e) {
        assertEquals(HttpStatus.NOT_FOUND, e.getStatusCode());
        throw e;
        }
    }   
}

1. 用随机端口启动服务器

@WebIntegrationTest(value={"server.port=0"}) 或者 @WebIntegrationTest("server.port=0") 或者 @WebIntegrationTest(randomPort=true)

使用端口

@Value("${local.server.port}")
private int port;
rest.getForObject(
"http://localhost:{port}/bogusPage", String.class, port);

2. 使用Selenium测试HTML页面

  1. 添加org.seleniumhq.selenium依赖

  2. 代码里使用

    1> 配置

    /* 在Spring Boot里使用Selenium测试的模板 */
     @RunWith(SpringJUnit4ClassRunner.class)
     @SpringApplicationConfiguration(
     classes=ReadingListApplication.class)
     @WebIntegrationTest(randomPort=true)
         public class ServerWebTests {
         private static FirefoxDriver browser;
         @Value("${local.server.port}")
         private int port;
    
         //配置Firefox驱动
         @BeforeClass
         public static void openBrowser() {
             browser = new FirefoxDriver();
             browser.manage().timeouts()
             .implicitlyWait(10, TimeUnit.SECONDS);
         }
    
         //关闭浏览器
         @AfterClass
         public static void closeBrowser() {
             browser.quit();
         }
     }
    

    2> 测试

    用Selenium测试阅读列表应用程序
     @Test
     public void addBookToEmptyList() {
         String baseUrl = "http://localhost:" + port;
         browser.get(baseUrl);
         assertEquals("You have no books in your book list", 
                         browser.findElementByTagName("div").getText());
    
         //填充并发送表单                
         browser.findElementByName("title").sendKeys("BOOK TITLE");
         browser.findElementByName("author").sendKeys("BOOK AUTHOR");
         browser.findElementByName("isbn").sendKeys("1234567890");
         browser.findElementByName("description").sendKeys("DESCRIPTION");
         browser.findElementByTagName("form").submit();
    
         //判断列表中是否包含新书
         WebElement dl = browser.findElementByCssSelector("dt.bookHeadline");
         assertEquals("BOOK TITLE by BOOK AUTHOR (ISBN: 1234567890)", dl.getText());
         WebElement dt = browser.findElementByCssSelector("dd.bookDescription");
         assertEquals("DESCRIPTION", dt.getText());
     }
    

备注:书上版本比较老,下面补充下新版本的测试方法。 例子摘自segmentfault_chenatu的文章 (仅适用spring-boot 1.4版本以后的写法):

直接调用接口函数进行测试:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApiTest {
    @Autowired
    MessageApi messageApi;
    ...

测试controller:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class ControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testControllerMethods() {
        MvcResult result = mockMvc.perform(get("/get-receive-message-abstracts").param("siteId", "webtrn").param("uid", "lucy")
                    .param("limit", "100")).andExpect(status().isOk())
                    .andExpect(jsonPath("$", hasSize(10))).andExpect(jsonPath("$[9].title", is("hello0"))).andReturn();
    }

mockito使用参考:

Mockito教程

SpringBoot与JUnit+Mockito 单元测试

© 著作权归作者所有

共有 人打赏支持
文小杰

文小杰

粉丝 13
博文 3
码字总数 4017
作品 0
长沙
程序员
私信 提问
分布式、微服务架构Spring Boot入门及实例介绍

spring boot入门 -- 介绍和第一个例子 “越来越多的企业选择使用spring boot 开发系统,spring boot牛在什么地方?难不难学?心动不如行动,让我们一起开始学习吧!” 使用Spring boot ,可以...

尘光掠影
06/04
0
0
新书上架:《Spring Boot 开发实战》(基于 Kotlin + Gradle + Spring Boot 2.0 的企业级服务端开发实战)

新书上架:《Spring Boot 开发实战》 — 基于 Kotlin + Gradle + Spring Boot 2.0 的企业级服务端开发实战 京东下单链接 https://item.jd.com/31178320122.html 天猫下单链接 https://detail...

程序员诗人
08/05
0
0
给spring-boot测试提供unitils支持的开源项目

一、unitils测试框架优缺点介绍 在unitils的支持下,xml配置的spring项目在测试时,有如下好处: 1、利用注解@DataSet、@ExpectedDataSet来准备数据和校验结果数据,每次运行测试用例不用重新...

yangjianzhou
07/09
0
0
实践Jenkins集成Cobertura自动化构建SpringBoot工程

热文推荐: 你的微服务敢独立交付么? 理解JWT的使用场景和优劣 从Spring-Session源码看Session机制的实现细节 理解使用 JWT 设计的单点登录系统 JDK 1.5 - 1.8 各版本的新特性总结 Spring B...

程序猿DD
04/28
0
0
Spring Boot实战与原理分析

Spring Boot实战与原理分析 1:Spring Boot概述与课程概要介绍 2:Spring4 快速入门 3:Spring4 扩展分析(一) 4:Spring4 扩展分析(二) 5:Spring Boot 快速入门 6:Spring Boot 配置分析...

刘宗泽
06/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周二乱弹 —— 其实我在地板也睡不着

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @witt-z :分享歌词: 阴天 在不开灯的房间,当所有思绪都一点一点沉淀。 分享莫文蔚的单曲《阴天》: 《阴天》- 莫文蔚 手机党少年们想听歌,...

小小编辑
10分钟前
11
3
微服务分布式事务实现

https://www.processon.com/view/link/5b2144d7e4b001a14d3d2d30

WALK_MAN
今天
3
0
《大漠烟尘》读书笔记及读后感文章3700字

《大漠烟尘》读书笔记及读后感文章3700字: 在这个浮躁的社会里,你有多久没有好好读完一本书了? 我们总觉得自己和别人不一样,所以当看到别人身上的问题时,很少有“反求诸己”,反思自己。...

原创小博客
今天
4
0
大数据教程(9.5)用MR实现sql中的jion逻辑

上一篇博客讲解了使用jar -jar的方式来运行提交MR程序,以及通过修改YarnRunner的源码来实现MR的windows开发环境提交到集群的方式。本篇博主将分享sql中常见的join操作。 一、需求 订单数据表...

em_aaron
今天
3
0
十万个为什么之什么是resultful规范

起源 越来越多的人开始意识到,网站即软件,而且是一种新型的软件。这种"互联网软件"采用客户端/服务器模式,建立在分布式体系上,通过互联网通信,具有高延时(high latency)、高并发等特点...

尾生
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部