|
| 1 | +# 简介 |
| 2 | + |
| 3 | +## 什么是 MyBatis-Spring-Boot-Starter-Test? |
| 4 | + |
| 5 | +MyBatis-Spring-Boot-Starter-Test 为 [MyBatis-Spring-Boot-Starter](http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/) 中的 MyBatis 组件提供测试用例。 |
| 6 | + |
| 7 | +使用它你将可以做到: |
| 8 | + |
| 9 | +* 可以使用 `@MybatisTest` 单独为 MyBatis 组件进行测试 |
| 10 | +* 在测试 MyBatis 组件时,可以导入依赖 |
| 11 | + |
| 12 | +TheMyBatis-Spring-Boot-Starter-Test 要求以下版本: |
| 13 | + |
| 14 | +| MyBatis-Spring-Boot-Starter-Test | Spring Boot | Java | |
| 15 | +| -------------------------------- | ------------- | --------- | |
| 16 | +| **2.3** | 2.5 或更高 | 8 或更高 | |
| 17 | +| **2.2** | 2.5 - 2.7 | 8 或更高 | |
| 18 | +| **2.1** | 2.1 - 2.4 | 8 或更高 | |
| 19 | +| **~~2.0 (EOL)~~** | ~~2.0 或 2.1~~ | ~~8 或更高~~ | |
| 20 | +| **~~1.3 (EOL)~~** | ~~1.5~~ | ~~6 或更高~~ | |
| 21 | +| **~~1.2 (EOL)~~** | ~~1.4~~ | ~~6 或更高~~ | |
| 22 | + |
| 23 | +## 安装 |
| 24 | + |
| 25 | +### Maven |
| 26 | + |
| 27 | +如果你使用 Maven,只需要将下面的依赖放入你的 `pom.xml`: |
| 28 | + |
| 29 | +```xml |
| 30 | +<dependency> |
| 31 | + <groupId>org.mybatis.spring.boot</groupId> |
| 32 | + <artifactId>mybatis-spring-boot-starter-test</artifactId> |
| 33 | + <version>${project.version}</version> |
| 34 | + <scope>test</scope> |
| 35 | +</dependency> |
| 36 | +``` |
| 37 | + |
| 38 | +### Gradle |
| 39 | + |
| 40 | +如果使用 Gradle,在 `build.gradle` 中加入以下内容: |
| 41 | + |
| 42 | +```groovy |
| 43 | +dependencies { |
| 44 | + testCompile("org.mybatis.spring.boot:mybatis-spring-boot-starter-test:${project.version}") |
| 45 | +} |
| 46 | +``` |
| 47 | + |
| 48 | +## 使用 @MybatisTest |
| 49 | + |
| 50 | +当你想对 MyBatis 组件进行测试时,可以使用 `@MybatisTest` (Mapper 接口与 `SqlSession`)。 |
| 51 | +默认情况下, 它将会配置 MyBatis(MyBatis-Spring)组件(`SqlSessionFactory` 与 `SqlSessionTemplate`),配置 MyBatis mapper 接口和内存中的内嵌的数据库。 |
| 52 | +MyBatis 测试默认情况下基于事务,且在测试的结尾进行回滚。 |
| 53 | +更多相关的信息可参见 [Spring 参考文档](https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testcontext-tx-enabling-transactions) 。 |
| 54 | +再者,普遍情况下 `@Component` beans 将不会被载入 `ApplicationContext` 。 |
| 55 | + |
| 56 | +### 对 Mapper 接口进行测试 |
| 57 | + |
| 58 | +如果你想对下面的 Mapper 接口进行测试,你只需要将 `@MybatisTest` 添加在测试类上。 |
| 59 | + |
| 60 | +Mapper 接口: |
| 61 | + |
| 62 | +```java |
| 63 | +package sample.mybatis.mapper; |
| 64 | + |
| 65 | +import org.apache.ibatis.annotations.Mapper; |
| 66 | +import org.apache.ibatis.annotations.Param; |
| 67 | +import org.apache.ibatis.annotations.Select; |
| 68 | +import sample.mybatis.domain.City; |
| 69 | + |
| 70 | +@Mapper |
| 71 | +public interface CityMapper { |
| 72 | + |
| 73 | + @Select("SELECT * FROM CITY WHERE state = #{state}") |
| 74 | + City findByState(@Param("state") String state); |
| 75 | + |
| 76 | +} |
| 77 | +``` |
| 78 | + |
| 79 | +测试类: |
| 80 | + |
| 81 | +```java |
| 82 | +package sample.mybatis.mapper; |
| 83 | + |
| 84 | +import org.junit.jupiter.api.Test; |
| 85 | +import org.junit.runner.RunWith; |
| 86 | +import org.mybatis.spring.boot.test.autoconfigure.MybatisTest; |
| 87 | +import sample.mybatis.domain.City; |
| 88 | +import org.springframework.beans.factory.annotation.Autowired; |
| 89 | +import org.springframework.test.context.junit4.SpringRunner; |
| 90 | + |
| 91 | +import static org.assertj.core.api.Assertions.assertThat; |
| 92 | + |
| 93 | +@RunWith(SpringRunner.class) |
| 94 | +@MybatisTest |
| 95 | +public class CityMapperTest { |
| 96 | + |
| 97 | + @Autowired |
| 98 | + private CityMapper cityMapper; |
| 99 | + |
| 100 | + @Test |
| 101 | + public void findByStateTest() { |
| 102 | + City city = cityMapper.findByState("CA"); |
| 103 | + assertThat(city.getName()).isEqualTo("San Francisco"); |
| 104 | + assertThat(city.getState()).isEqualTo("CA"); |
| 105 | + assertThat(city.getCountry()).isEqualTo("US"); |
| 106 | + } |
| 107 | + |
| 108 | +} |
| 109 | +``` |
| 110 | + |
| 111 | +### DAO 模式下的测试 |
| 112 | + |
| 113 | +如果你为下面的 DAO 类创建测试,你只需要将 `@MybatisTest` 和 `@Import` 添加在你的测试类上。 |
| 114 | + |
| 115 | +DAO 类: |
| 116 | + |
| 117 | +```java |
| 118 | +package sample.mybatis.dao; |
| 119 | + |
| 120 | +import org.apache.ibatis.session.SqlSession; |
| 121 | +import sample.mybatis.domain.City; |
| 122 | + |
| 123 | +import org.springframework.stereotype.Component; |
| 124 | + |
| 125 | +@Component |
| 126 | +public class CityDao { |
| 127 | + |
| 128 | + private final SqlSession sqlSession; |
| 129 | + |
| 130 | + public CityDao(SqlSession sqlSession) { |
| 131 | + this.sqlSession = sqlSession; |
| 132 | + } |
| 133 | + |
| 134 | + public City selectCityById(long id) { |
| 135 | + return this.sqlSession.selectOne("selectCityById", id); |
| 136 | + } |
| 137 | + |
| 138 | +} |
| 139 | +``` |
| 140 | + |
| 141 | +测试类: |
| 142 | + |
| 143 | +```java |
| 144 | +package sample.mybatis.dao; |
| 145 | + |
| 146 | +import org.junit.jupiter.api.Test; |
| 147 | +import org.junit.runner.RunWith; |
| 148 | +import org.mybatis.spring.boot.test.autoconfigure.MybatisTest; |
| 149 | +import org.springframework.beans.factory.annotation.Autowired; |
| 150 | +import org.springframework.context.annotation.Import; |
| 151 | +import org.springframework.test.context.junit4.SpringRunner; |
| 152 | +import sample.mybatis.domain.City; |
| 153 | + |
| 154 | +import static org.assertj.core.api.Assertions.assertThat; |
| 155 | + |
| 156 | +@RunWith(SpringRunner.class) |
| 157 | +@MybatisTest |
| 158 | +@Import(CityDao.class) |
| 159 | +public class CityDaoTest { |
| 160 | + |
| 161 | + @Autowired |
| 162 | + private CityDao cityDao; |
| 163 | + |
| 164 | + @Test |
| 165 | + public void selectCityByIdTest() { |
| 166 | + City city = cityDao.selectCityById(1); |
| 167 | + assertThat(city.getName()).isEqualTo("San Francisco"); |
| 168 | + assertThat(city.getState()).isEqualTo("CA"); |
| 169 | + assertThat(city.getCountry()).isEqualTo("US"); |
| 170 | + } |
| 171 | + |
| 172 | +} |
| 173 | +``` |
| 174 | + |
| 175 | +## 使用真实的数据库 |
| 176 | + |
| 177 | +内嵌的数据库通常在测试上表现良好,因为们很快,且不需要安装一些开发工具。 |
| 178 | +然而如果你希望使用真实的数据库,你可以像下面这样使用 `@AutoConfigureTestDatabase` : |
| 179 | + |
| 180 | +```java |
| 181 | +package sample.mybatis.mapper; |
| 182 | +// ... |
| 183 | +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; |
| 184 | + |
| 185 | +@RunWith(SpringRunner.class) |
| 186 | +@MybatisTest |
| 187 | +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) |
| 188 | +public class CityMapperTest { |
| 189 | + // ... |
| 190 | +} |
| 191 | +``` |
| 192 | + |
| 193 | +## 避免探测到真实的 @SpringBootApplication |
| 194 | + |
| 195 | + `@MybatisTest` 在默认情况下将会探测到带有 `@SpringBootApplication` 的类。 |
| 196 | +因此,由于 bean 定义的一些方法,可能会发生一些意想不到的错误,或者一些不必要的组件被装入 `ApplicationContext` 。 |
| 197 | +为了避免这种情况,我们可以在与测试类相同的包中创建带有 `@SpringBootApplication` 的类。 |
| 198 | + |
| 199 | +```java |
| 200 | +package sample.mybatis.mapper; |
| 201 | + |
| 202 | +import org.springframework.boot.autoconfigure.SpringBootApplication; |
| 203 | + |
| 204 | +@SpringBootApplication |
| 205 | +class MapperTestApplication { |
| 206 | + |
| 207 | +} |
| 208 | +``` |
| 209 | + |
| 210 | +## 与其他 @***Test 一起使用 |
| 211 | + |
| 212 | +如果 `@MybatisTest` 与其他的 `@***Test` 一起使用(例如: `@WebMvcTest`), |
| 213 | +请考虑使用 `@AutoConfigureMybatis` ,因为不能在同一测试中指定两个或多个`@***Test` 注解。 |
| 214 | + |
| 215 | +测试的目标类: |
| 216 | + |
| 217 | +```java |
| 218 | +@RestController |
| 219 | +public class PingController { |
| 220 | + PingMapper mapper; |
| 221 | + |
| 222 | + PingController(PingMapper mapper) { |
| 223 | + this.mapper = mapper; |
| 224 | + } |
| 225 | + |
| 226 | + @GetMapping("ping") |
| 227 | + String ping() { |
| 228 | + return mapper.ping(); |
| 229 | + } |
| 230 | +} |
| 231 | +``` |
| 232 | + |
| 233 | +```java |
| 234 | +@Mapper |
| 235 | +public interface PingMapper { |
| 236 | +@Select("SELECT 'OK'") |
| 237 | + String ping(); |
| 238 | +} |
| 239 | +``` |
| 240 | + |
| 241 | +测试类: |
| 242 | + |
| 243 | +```java |
| 244 | +@RunWith(SpringRunner.class) |
| 245 | +@WebMvcTest |
| 246 | +@AutoConfigureMybatis // 替代 @MybatisTest |
| 247 | +public class PingTests { |
| 248 | + |
| 249 | + @Autowired |
| 250 | + private MockMvc mvc; |
| 251 | + |
| 252 | + @Test |
| 253 | + public void ping() throws Exception { |
| 254 | + this.mvc.perform(get("/ping")) |
| 255 | + .andExpect(status().isOk()) |
| 256 | + .andExpect(content().string("OK")); |
| 257 | + } |
| 258 | + |
| 259 | +} |
| 260 | +``` |
| 261 | + |
| 262 | +## 在 JUnit 5 上使用 @MybatisTest |
| 263 | + |
| 264 | +`@MybatisTest` 可以在 JUnit 5 上使用: |
| 265 | + |
| 266 | +```java |
| 267 | +@ExtendWith(SpringExtension.class) |
| 268 | +@MybatisTest |
| 269 | +public class CityMapperTest { |
| 270 | + // ... |
| 271 | +} |
| 272 | +``` |
| 273 | + |
| 274 | +自 2.0.1 起, `@ExtendWith(SpringExtension.class)` 可以像下面这样被忽略: |
| 275 | + |
| 276 | +```java |
| 277 | +@MybatisTest |
| 278 | +public class CityMapperTest { |
| 279 | + // ... |
| 280 | +} |
| 281 | +``` |
| 282 | + |
| 283 | +## 附录 |
| 284 | + |
| 285 | +### 导入的自动配置 |
| 286 | + |
| 287 | + `@MybatisTest` 将会导入以下自动配置的类: |
| 288 | + |
| 289 | +* `org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration` |
| 290 | +* `org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration` |
| 291 | +* `org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration` |
| 292 | +* `org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration` |
| 293 | +* `org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration` |
| 294 | +* `org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration` |
| 295 | +* `org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration` |
| 296 | +* `org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration` |
| 297 | +* `org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration` |
| 298 | +* `org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration` |
| 299 | + |
| 300 | +### 可运行的样例 |
| 301 | + |
| 302 | +项目(为每个类型)提供了两个样例供使用: |
| 303 | + |
| 304 | +| 分类 | 样例 | 描述 | |
| 305 | +|:------ |:----------------------------------------------------------------------------------------------------------------------------------- |:--------------------------------------------------------------------- | |
| 306 | +| 核心 | [样例1](https://github.com/mybatis/spring-boot-starter/tree/master/mybatis-spring-boot-samples/mybatis-spring-boot-sample-annotation) | 展示了最简单的场景,只有一个 mapper 和一个注入 mapper 的组件。这就是我们在“快速入门”部分看到的例子。 | |
| 307 | +| | [样例2](https://github.com/mybatis/spring-boot-starter/tree/master/mybatis-spring-boot-samples/mybatis-spring-boot-sample-xml) | 展示了如何在 XML 文件中使用一个带有语句的 Mapper,并且也有使用 `SqlSessionTemplate` 的 DAO 的示例。 | |
| 308 | +| JVM 语言 | [样例3](https://github.com/mybatis/spring-boot-starter/tree/master/mybatis-spring-boot-samples/mybatis-spring-boot-sample-kotlin) | 展示了如何和 kotlin 一同使用。 | |
| 309 | +| | [样例4](https://github.com/mybatis/spring-boot-starter/tree/master/mybatis-spring-boot-samples/mybatis-spring-boot-sample-groovy) | 展示了如何和 groovy 一同使用。 | |
0 commit comments