# 编写Spring应用

## `@SpringBootApplication` 注解

1. `@EnableAutoConfiguration`：
    - 这个注解让 Spring Boot 根据项目中的依赖，自动配置 Spring 应用程序。Spring Boot 提供了大量的自动配置支持，帮助我们省去手动配置许多常见的功能。
    - 例如，如果你的项目中加入了 `spring-boot-starter-web` 依赖，Spring Boot 会自动配置一个嵌入式的 Tomcat 服务器和一些常见的 Web 功能。
2. `@ComponentScan`：
    - 这个注解启用 Spring 的组件扫描机制。它会扫描当前类所在的包及其子包，自动发现并注册 `@Component`、`@Service`、`@Repository`、`@Controller` 等注解标注的类。
    - 通过 `@ComponentScan`，你不需要手动指定要扫描的包，Spring Boot 会自动扫描当前包及其子包下的所有组件。
3. `@Configuration`：
    - 这个注解表示该类是一个 Spring 配置类，类似于 XML 配置文件，用于定义 Spring 应用的 Bean 配置。
    - 该类可以包含 `@Bean` 注解的方法，返回要管理的 Bean。

## `@SpringBootTest` 注解
`@SpringBootTest` 注解是用于测试 Spring Boot 应用的一个重要注解，它提供了一种方便的方式来启动 Spring Boot 应用上下文，并对整个 Spring Boot 应用进行集成测试。这个注解本身也包含了多个注解，它使得我们能够在测试类中创建一个完整的 Spring 容器来进行集成测试。

具体来说，`@SpringBootTest` 是一个组合注解，它整合了以下几个主要的注解：

1. `@ContextConfiguration`：
    - `@ContextConfiguration` 注解用于加载 Spring 配置文件或者配置类，在测试时会初始化 Spring 容器。`@SpringBootTest` 默认会加载 Spring Boot 应用的主配置类（即包含 `@SpringBootApplication` 注解的类），作为 Spring 容器的上下文。
    - 它的作用是让测试类能够加载到 Spring 配置并创建一个完整的应用上下文。
2. `@TestExecutionListeners`：
    - 该注解指定了测试执行时的监听器。在 Spring 测试框架中，`@TestExecutionListeners` 会提供某些扩展功能，如事务管理、环境配置等，但它的实际作用在大多数测试中不太明显，通常由 Spring Boot 自动配置。
3. `@DirtiesContext`：
    - 这个注解会告诉 Spring 在测试执行之后清除（或重置）应用上下文，通常用于测试中的应用上下文需要被清理或重置，以避免测试间的相互影响。`@SpringBootTest` 会根据需要处理上下文的清理工作。
4. `@BootstrapWith`：
    - 这个注解是用于引导测试的，它会指定 `SpringBootTestContextBootstrapper` 来启动 Spring Boot 测试上下文。这是一个 Spring Boot 测试框架中的内部机制，用于初始化应用上下文并准备测试。

## 测试页面
编写控制界面，返回`index.html`

```java
@RequestMapping
@Controller
public class HomeController {

    @Operation(summary = "主页内容")
    @GetMapping("index")
    public String index() {
        return "index";
    }
}
```

测试页面返回结果

```java
@WebMvcTest(HomeController.class)
class HomeControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void index() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/"))// 访问路径
                .andExpect(MockMvcResultMatchers.status().isOk())// 判断状态是否成功
                .andExpect(MockMvcResultMatchers.view().name("index"))// 判断视图名称是否是index
                // 是否包含字段
                .andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("欢迎。。。")));
    }
}
```

访问index的页面

```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Index 测试页面</title>
    </head>
    <body>
        <h1>欢迎。。。</h1>
        <img alt="" th:src="@{/images/icon_3.png}">
        <img alt="通常MVC项目静态资源放在 static/images 下" src="images/index/diannao.png">
    </body>
</html>

```

> 静态资源问题，如果用户是访问静态资源，如果直接写在`template`方式引入资源会找不到，因为默认资源都放在`static`目录下载的。
>

### 什么时候该用这种测试
#### 1. 验证控制器的业务逻辑
+ `@WebMvcTest` 本质上是用来验证 **控制器层的行为**，而不是渲染出来的页面。它帮助你测试控制器是否能正确处理 HTTP 请求、是否返回正确的视图名称或正确的响应状态码等。
+ 比如，你可以测试一个 `GET /home` 请求是否返回了预期的视图名称 `"index"`，或者返回的状态码是否是 `200 OK`，而这些正是你在控制器中希望验证的部分。**这与页面渲染无关**，所以它不会显示页面内容，也不会出现渲染时的误差。

#### 2. 关注点分离
+ 使用 `@WebMvcTest` 进行单元测试能够将 **Web 层** 与 **业务逻辑层**（Service、Repository）进行解耦。通过这种方式，你可以专注于测试控制器层的 HTTP 请求和响应，而不需要担心 Service 层的逻辑是否正确，或者数据库的连接是否正常。
+ 控制器层和页面渲染是两个不同的关注点。**控制器层的目标是处理请求、确定视图名称、返回模型数据**等，而页面渲染本身通常由前端技术或模板引擎处理，更多是浏览器中的前端渲染过程。

#### 3. 通过 Mock 数据模拟请求和响应
+ 在 `@WebMvcTest` 中，`MockMvc` 会模拟请求并验证响应，它不会执行实际的页面渲染或显示，只会检查你定义的 **控制器输出** 是否符合预期。因此，它能有效避免浏览器渲染过程中的误差。
+ 比如，`MockMvc` 可以验证你的控制器是否正确返回了某个 HTML 页面的视图名称，而不用关注 HTML 的具体内容。如果你的目标是确保控制器的逻辑没有错误，这种方式是非常高效的。

#### 4. 测试时更快速且更简洁
+ 通过 `@WebMvcTest` 测试时，你只加载 Web 层的相关组件，不需要启动整个应用的上下文，因此测试速度通常更快。
+ 它让你能够快速定位问题。例如，如果测试失败，你可以很清楚地知道是控制器中的视图名称、请求参数的处理，还是其他的 HTTP 相关操作出了问题。反而如果进行实际的浏览器渲染测试，可能涉及到浏览器兼容性、前端细节等问题，会增加复杂度。

#### 5. 避免不必要的页面渲染
+ 事实上，控制器的核心功能并不依赖于页面渲染。控制器应该保证的是：
    - 正确处理请求
    - 返回适当的视图名称和模型数据
    - 设置正确的响应状态码和其他 HTTP 相关的参数
+ 页面渲染通常是通过模板引擎（如 Thymeleaf、JSP）完成的，而 `@WebMvcTest` 仅仅验证的是 **控制器的行为**，例如它返回的是正确的视图名称（而不是真的生成 HTML 页面）。

#### 6. 不同类型的测试互为补充
+ 你可以把 

```java
@WebMvcTest
```

 和 端到端测试（如集成测试或 UI 测试）结合起来使用：

    - `@WebMvcTest` 用于测试控制器的行为、请求路径、视图名称等。
    - **端到端测试** 可以通过实际浏览器或工具（如 Selenium）来模拟用户操作，查看页面是否正确渲染，验证 HTML 是否按预期显示。

## 
