(001)springboot中测试的基础知识以及接口和Controller的测试

Posted 明月之诗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(001)springboot中测试的基础知识以及接口和Controller的测试相关的知识,希望对你有一定的参考价值。

  (一)springboot中测试的基础知识

  (1)添加starter-test依赖,范围指定为test,只在执行测试时生效

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>

  完整pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.edu.spring</groupId>
    <artifactId>springboot_web</artifactId>
    <version>1.0.0</version>

    <name>springboot_web</name>
    <!-- FIXME change it to the project\'s website -->
    <url>http://www.example.com</url>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>
View Code

  (2)新建类UserDao.java,并添加测试类

package com.edu.spring.springboot.dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {

    public Integer  addUser(String username){
        System.out.println("user dao addUser["+username+"]");
        if(username==null){
            return 0;
        }
        return 1;
    }
}
View Code

  选中要测试的类 -> 右键 -> new -> 输入ju,选择JUnit Test Case  -> next -> 选择填写正确信息 -> next -> 选择测试的方法 -> finish

   UserDaoTest.java,测试类需要添加注解@RunWith(SpringRunner.class)、@SpringBootTest

package com.edu.spring.springboot.dao;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserDaoTest {

    @Autowired
    private UserDao userDao;
    
    @Test
    public void testAddUser() {
        Assert.assertEquals(Integer.valueOf(1), userDao.addUser("root"));
        Assert.assertEquals(Integer.valueOf(0), userDao.addUser(null));
    }

}
View Code

  运行如下:

   (3)在测试环境创建bean需要用@TestConfiguration,并且该注解只在测试环境下有效

  TestBeanConfiguration.java(src/test/java),创建Runnable类型的bean

package com.edu.spring.springboot.dao;

import org.springframework.context.annotation.Bean;
import org.springframework.boot.test.context.TestConfiguration;

@TestConfiguration
public class TestBeanConfiguration {

    @Bean
    public Runnable createRunnable(){
        return () -> {};
    }
}
View Code

  ApplicationContextTest.java(src/test/java),指定测试环境的配置类 @SpringBootTest(classes=TestBeanConfiguration.class)

package com.edu.spring.springboot.dao;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.Assert;

@RunWith(SpringRunner.class)
@SpringBootTest(classes=TestBeanConfiguration.class)
public class ApplicationContextTest {

    @Autowired
    private ApplicationContext context;
    
    @Test
    public void testNull(){
        Assert.notNull(context.getBean(Runnable.class),"获取Runnable.class的bean出错");
    }
}
View Code

  运行结果如下:

   不在测试环境无法获取@TestConfiguration中创建的bean,如下图

  (4)springboot会优先加载测试环境下的application.properties,测试环境下没有才会加载正常环境下的

  application.properties(src/test/resources)

app.name=springboottest

  EnvTest.java(src/test/java),测试环境使用ConfigurableEnvironment获取配置文件属性

package com.edu.spring.springboot.dao;


import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class EnvTest {
    
    @Autowired
    private ConfigurableEnvironment env;
    
    @Test
    public void testValue(){
        Assert.assertEquals("springboottest",env.getProperty("app.name"));
    }
}
View Code

  运行结果如下:

   删除测试环境的application.properties,在正常环境的application.properties添加如下配置

app.name=springboot

  EnvTest.java修改为:

Assert.assertEquals("springboot",env.getProperty("app.name"));

  运行结果如下:

  (5)运行时指定配置@SpringBootTest(properties = {"app.admin.name=zhangsan","app.admin.passwd=123456"})

  EnvTest.java

package com.edu.spring.springboot.dao;


import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(properties = {"app.admin.name=zhangsan","app.admin.passwd=123456"})
public class EnvTest {
    
    @Autowired
    private ConfigurableEnvironment env;
    
    @Test
    public void testValue(){
        Assert.assertEquals("zhangsan",env.getProperty("app.admin.name"));
        Assert.assertEquals("123456",env.getProperty("app.admin.passwd"));
    }
}
View Code

  运行结果如下:

  (二)springboot中测试接口,使用注解@MockBean 和 BDDMockito类

  接口UserMapper.java

package com.edu.spring.springboot.mapper;

public interface UserMapper {
    public Integer addUser(String username);
}
View Code

  测试类UserMapperTest.java,@MockBean注入接口,BDDMockito给出预测

package com.edu.spring.springboot.mapper;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.BDDMockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @MockBean
    private UserMapper userMapper;
    
    @Test(expected=NullPointerException.class)
    public void createUserTest(){
        
        BDDMockito.given(userMapper.addUser("admin")).willReturn(Integer.valueOf(1));
        BDDMockito.given(userMapper.addUser("")).willReturn(Integer.valueOf(0));
        BDDMockito.given(userMapper.addUser(null)).willThrow(NullPointerException.class);
        
        Assert.assertEquals(Integer.valueOf(1), userMapper.addUser("admin"));
        Assert.assertEquals(Integer.valueOf(0), userMapper.addUser(""));
        Assert.assertEquals(Integer.valueOf(0), userMapper.addUser(null));
    }

}
View Code

  或者在初始化方法中给出预测:

package com.edu.spring.springboot.mapper;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.BDDMockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @MockBean
    private UserMapper userMapper;
    
    @Before
    public void init(){
        BDDMockito.given(userMapper.addUser("admin")).willReturn(Integer.valueOf(1));
        BDDMockito.given(userMapper.addUser("")).willReturn(Integer.valueOf(0));
        BDDMockito.given(userMapper.addUser(null)).willThrow(NullPointerException.class);
    }
    
    @Test(expected=NullPointerException.class)
    public void createUserTest(){
        Assert.assertEquals(Integer.valueOf(1), userMapper.addUser("admin"));
        Assert.assertEquals(Integer.valueOf(0), userMapper.addUser(""));
        Assert.assertEquals(Integer.valueOf(0), userMapper.addUser(null));
    }

}
View Code

  运行结果如下:

  (三)springboot中测试Controller的两种方式:TestRestTemplate 和 MockMvc,这里从构建测试环境分3种进行说明

  BookController.java

package com.edu.spring.springboot;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BookController {

    @GetMapping("/book/home")
    public String home(){
        return "book home";
    }
    
    @GetMapping("/book/show")
    public String show(String id){
        return "book"+id;
    }
}
View Code

  (1)@SpringBootTest注解,指定webEnvironment 和 注入TestRestTemplate

  BookControllerTest.java

package com.edu.spring.springboot;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class BookControllerTest {

    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    public void testHome() {
        String actual=restTemplate.getForObject("/book/home",String.class);
        Assert.assertEquals("book home", actual);
    }
    
    @Test
    public void testShow() {
        String actual=restTemplate.getForObject("/book/show?id=100",String.class);
        Assert.assertEquals("book100", actual);
    }

}
View Code

  运行结果如下:

  (2)@WebMvcTest注解,指定controllers 和 注入MockMvc 

  BookControllerTest2.java

package com.edu.spring.springboot;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

@RunWith(SpringRunner.class)
@WebMvcTest(controllers=BookController.class)
public class BookControllerTest2 {

    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void testHome() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/book/home")).andExpect(MockMvcResultMatchers.status().isOk());
        mockMvc.perform(MockMvcRequestBuilders.get("/book/home")).andExpect(MockMvcResultMatchers.content().string("book home"));
    }
    
    @Test
    public void testShow() throws Exception{
        
        mockMvc.perform(MockMvcRequestBuilders.get("/book/show").param("id","100")).andExpect(MockMvcResultMatchers.status().isOk());
        mockMvc.perform(MockMvcRequestBuilders.get("/book/show").param("id","100")).andExpect(MockMvcResultMatchers.content().string("book100"));
    }

}
View Code

  运行结果如下:

  假如在 BookController.java 中注入 UserDao,即添加如下代码,再次测试会报错,因为@WebMvcTest不会加载整个spring容器

@Autowired UserDao userDao;

  运行结果如下

  (3)使用@SpringBootTest、@AutoConfigureMockMvc 注解,注入MockMvc

  BookControllerTest3.java

package com.edu.spring.springboot;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class BookControllerTest3 {

    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void testHome() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/book/home")).andExpect(MockMvcResultMatchers.status().isOk());
        mockMvc.perform(MockMvcRequestBuilders.get("/book/home")).andExpect(MockMvcResultMatchers.content().string("book home"));
    }
    
    @Test
    public void testShow() throws Exception{
        
        mockMvc.perform(MockMvcRequestBuilders.get("/book/show").param("id","100")).andExpect(MockMvcResultMatchers.status().isOk());
        mockMvc.perform(MockMvcRequestBuilders.get("/book/show").param("id","100")).andExpect(MockMvcResultMatchers.content().string("book100"));
    }

}
View Code

  运行结果如下:

  总结:

  @SpringBootTest 会加载整个spring容器

  @WebMvcTest 不需要运行在web环境下,但是需要指定controllers,这种方法只测试controller,不会加载整个spring容器

  如果依然使用MockMvc,需要添加@SpringBootTest 和 @AutoConfigureMockMvc注解 

  @SpringBootTest 和 @WebMvcTest不能同时使用

 

 

 

  

以上是关于(001)springboot中测试的基础知识以及接口和Controller的测试的主要内容,如果未能解决你的问题,请参考以下文章

TestNG学习-001-基础理论知识

springboot-web进阶——单元测试

音视频连载-001基础学习篇- SDL 介绍以及工程配置

001 | 搭上SpringBoot自动注入源码分析专车

001.camunda入门(springboot集成篇)

001-SpringBoot2入门:一些官网链接参考和介绍