SpringBoot入门教程02——如何优雅地使用spring-boot-starter-test做单元测试

SpringBoot入门教程02——如何优雅地使用spring-boot-starter-test做单元测试

前言

看过一些springboot教程博客,单元测试这里的教程大都比较旧,还有一些博客甚至让exclusions掉spring-boot-starter-test下的包,然后重新引入junit4去做单元测试。

笔者认为这些方法不是不行,只是不够优雅,下面我们讲一下如何优雅地使用内置的spring-boot-starter-test做单元测试

环境说明

  • 我们使用第1节教程构建出的项目 传送门
  • springboot版本号2.3.1.RELEASE
  • pom文件直接使用Spring Assistant构建项目时生成的,一行都不需要改动

第一个测试案例

打开test/java目录,我们发现贴心的Spring Assistant已经帮我们构建好了第一个测试案例——SpringbootDemoApplicationTests

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class SpringbootDemoApplicationTests {
    
    

	@Test
	void contextLoads() {
    
    
	}

}

如果你是idea工具开发,在contextLoads()方法这一行最左边会有一个三角符号,点击即可运行该测试方法。

运行之后,我们可以看到控制台输出了一堆看不懂的日志,然后提示"Tests passed"

这时候你一定有以下2个疑问

  • @SpringBootTest注解究竟做了什么
  • 为什么内置测试案例的方法名叫contextLoads

@SpringBootTest注解究竟做了什么

我们对第一个测试案例进行一个改造,代码如下:

@Test
void contextLoads(ApplicationContext ctx) {
    
    
    System.out.println("Let's inspect the beans provided by Spring Boot:");
    String[] beanNames = ctx.getBeanDefinitionNames();
    System.out.println(String.format("Spring applicationtext has %d beans total !", beanNames.length));
    Arrays.sort(beanNames);
    for (String beanName : beanNames) {
    
    
        System.out.println(beanName);
    }
}

运行日志如下:

Let's inspect the beans provided by Spring Boot:
Spring applicationtext has 125 beans total !
applicationAvailability
applicationTaskExecutor
basicErrorController
beanNameHandlerMapping
beanNameViewResolver
characterEncodingFilter
...

我们可以发现spring容器中一共有125个beans,而且我们自定义的helloController也在里面。所以上一章的2个小问题就很好回答了

  • @SpringBootTest注解会模拟SpringBoot应用启动,创建ApplicationContext容器,并把内置的beans以及用户开发的beans注入到ApplicationContext容器中。
  • 以上过程我们可以称之为容器加载的过程,所以方法命名为contextLoads

既然我们自定义的helloController也在spring容器中,那我们该如何调用它呢?

调用SpringBoot应用中自定义的Controller

在src/test/java的com.henry包下新建controller包,再新建HelloControllerTest类,代码如下:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloControllerTest {
    
    
    @LocalServerPort
    private int port;

    private String baseUrl;
    private TestRestTemplate restTemplate;

    @BeforeEach
    public void setUp(){
    
    
        this.baseUrl="http://127.0.0.1:"+port;
        this.restTemplate = new TestRestTemplate();
    }

    @Test
    public void index() {
    
    
        System.out.println("request url is: "+baseUrl);
        ResponseEntity<String> response = restTemplate.getForEntity(baseUrl, String.class);
        System.out.println(response.getBody());
        Assertions.assertEquals(response.getBody(),"Welcome to Spring Boot!");
    }
}    

运行index方法,即可看到可以成功调用springboot应用中的helloController

下面我们对几个参数进行一个说明

  • webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT //指定一个随机端口,去启动内置的web应用服务器
  • @LocalServerPort 该注解会把springboot内置web应用服务器启动端口赋给其注解的字段,也就是port字段
  • @BeforeEach junit5新增注解,等同于junit4以前的@Before注解,会在@Test注解之前执行

如果webEnvironment不指定属性,那么@SpringBootTest注解只会初始化spring容器并注入beans,但是不会启动内置的web应用服务器。指定RANDOM_PORT就是随机端口,随机端口的好处是应用启动的时候也能玩。指定DEFINED_PORT用的就是配置文件中配置的端口,默认是8080,如果应用是运行状态,运行测试案例会端口冲突。

贴一下WebEnvironment源码,大家一看便知

public static enum WebEnvironment {
    
    
        MOCK(false),
        RANDOM_PORT(true),
        DEFINED_PORT(true),
        NONE(false);

        private final boolean embedded;

        private WebEnvironment(boolean embedded) {
    
    
            this.embedded = embedded;
        }

        public boolean isEmbedded() {
    
    
            return this.embedded;
        }
    }

猜你喜欢

转载自blog.csdn.net/l229568441/article/details/106910323