# SpringBoot单元测试实践

```java
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@Transactional
@Rollback(true)
public class HelloServiceTest {
 
    @Autowired
    private HelloService helloService;
 
    @Test
    public void sayHello() {
        helloService.sayHello("zhangsan");
        // XXX Asset
    }

```

1. `@SpringBootTest`启动了SpringBoot环境，`classes = Application.class`则扫描了该类下的所有的Bean
2. `@Transactional` 含有数据库操作，需要增加该注解
3. `@Rollback(true)` 数据库事务默认回滚，用来保障数据隔离

## 使用内存数据库 h2 + flayway为dao层测试

## mock feign client

Feign Client接口：

```java
@FeignClient(value = "baidu")
public interface BaiduApi {
    @GetMapping("index.html")
    String index();
}
```

上层业务逻辑：

```java
@Component
public class BaiduManager {
    @Resource
    private BaiduApi baiduApi;

    public String getIndex() {
        return baiduApi.index();
    }
}
```

单元测试：

```java
@SpringBootTest
class BaiduManagerTest {
    @Resource
    private BaiduManager baiduManager;

    // `@MockBean`会生成一个Mock对象，并取代已存在的相同类型的单例bean，如果不存在则添加
    @MockBean(name = "com.tenmao.utdemo.BaiduApi")
    private BaiduApi baiduApi;

    @Test
    void getIndex() {
        Mockito.when(baiduApi.index()).thenReturn("baidu index");

        String index = baiduManager.getIndex();
        Assertions.assertEquals("baidu index", index);
    }
}
```

注意：

* Mock对象并没有取代实际对象：`@MockBean(name = "com.tenmao.utdemo.BaiduApi")`需要设置name为全限定符

## @SpringBootTest 性能优化

1. `webEnvironment` 这个属性决定了测试类要不要启动一个 web 环境，说白了就是要不要启动一个 Tomcat 容器，可选的值为：
   * MOCK, 启动一个模拟的 Servlet 环境，这是默认值
   * RANDOM\_PORT，启动一个 Tomcat 容器，并监听一个随机的端口号
   * DEFINED\_PORT，启动一个 Tomcat 容器，并监听配置文件中定义的端口（未定义则默认监听8080）
   * NONE，不启动 Tomcat 容器。只需要通过指定 `@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)` 即可达到加速的效果。这时测试类启动时就只会初始化 Spring 上下文，不再启动 Tomcat 容器了!
2. `classes` 属性，用来指定运行测试类需要装载的 class 集合，如果不指定，那么会默认装载 `@SpringBootConfiguration` 注解标注的类。如果我们不指定classes属性，那么启动测试类时需要加载的Bean的数量和正常启动一次入口类(即有`@SpringBootApplication`注解的类)加载的 Bean 数量是一样的。
   * 特别是含有 `@PostConstruct` 注解指定的Bean以及实现了`CommandLineRunner`接口的Bean，他们可能会有很长的初始化时间。
   * 启动时，如果选择只加载需要的Bean上下文，就可以加快速度。
3. 使用`@ComponentScan`来指明Spring 扫描Bean的范围，也可以缩小Bean所扫描的范围
4. `@ContextConfiguration` 定义类级元数据，用于确定如何为集成测试加载和配置，简单的说就是通过该注解定义Spring容器在启动是需要加载的上下文（配置类、配置文件、实例化的Bean）,可以用于最小化测试，提升测试效率。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yangsx95.gitbook.io/notes/architect/dan-yuan-ce-shi/springboot-dan-yuan-ce-shi-shi-jian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
