文档章节

spring boot 测试

文小杰
 文小杰
发布于 2017/09/08 13:42
字数 1599
阅读 16
收藏 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 单元测试

© 著作权归作者所有

共有 人打赏支持
文小杰

文小杰

粉丝 12
博文 3
码字总数 4017
作品 0
长沙
程序员
给spring-boot测试提供unitils支持的开源项目

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

yangjianzhou
07/09
0
0
Spring Boot实战 目录

书名: Spring Boot实战 定价: 59.00元 出版社名称: 人民邮电出版社 出版日期:2016年8月 作者: Craig Walls ISBN编号: 9787115433145 内容简介 本书以Spring应用程序开发为中心,全面讲解如何...

程序员诗人
2017/04/01
0
0
springwwwhj8828com boot18088045700应用测试框架介绍

官方提供的测试框架spring-boot-test-starter,虽然提供了很多功能,但是在数据库层面,依旧存在问题,它强烈依赖于数据库中的数据,并且自身不具备数据初始化的能力。测试框架spring-test-d...

果博东方
07/20
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
IDEA 编译运行 Spring Boot 2.0 源码

下载代码切换分支 首先到上下的代码: 由于的发布版本代码都在上,所以需要使用命令查看所有的: 然后切换到名为的上: 这样,代码就被保存到本地分支上了。 源码编译 官方建议使用或者标准的...

九州暮云
09/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

关于组件化的最初步

一个工程可能会有多个版本,有国际版、国内版、还有针对各种不同的渠道化的打包版本、这个属于我们日常经常见到的打包差异化版本需求。 而对于工程的开发,比如以前的公司,分成了有三大块业...

DannyCoder
29分钟前
1
0
Spring的Resttemplate发送带header的post请求

private HttpHeaders getJsonHeader() { HttpHeaders headers = new HttpHeaders(); MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8"); ......

qiang123
昨天
2
0
Spring Cloud Gateway 之 Only one connection receive subscriber allowed

都说Spring Cloud Gateway好,我也来试试,可是配置了总是报下面这个错误: java.lang.IllegalStateException: Only one connection receive subscriber allowed. 困扰了我几天的问题,原来...

ThinkGem
昨天
25
0
学习设计模式——观察者模式

1. 认识观察者模式 1. 定义:定义对象之间一种一对多的依赖关系,当一个对象状态发生变化时,依赖该对象的其他对象都会得到通知并进行相应的变化。 2. 组织结构: Subject:目标对象类,会被...

江左煤郎
昨天
2
0
emoji

前言:随着iOS系统版本的升级,对原生emoji表情的支持也越来越丰富。emoji表情是unicode码中为表情符号设计的一组编码,当然,还有独立于unicode的另一套编码SBUnicode,在OS系统中,这两种编...

HeroHY
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部