前言:
在没有代码生成工具或尝试一门新的
ORM
框架时,当我们希望不去另外写 Service 和 Controller 来验证 DAO 层的代码不希望只通过接口请求的方式来验证时,这时候单元测试的方式就可以帮助我们满足这一需求。
[2022-08-01 17:31:39]
版本:springBoot 2.7.1
+junit5
(本文demo均通过机器验证)
注意事项
注:
以下测试时均可不用另外启动应用;
springboot-2.7.1
默认绑定junit5
而不再是junit4
,后期使用junit4
也可以使用操作:Add JUnit4 to classpath
若数据库密码配置是密文,解密密钥在启动参数里,先改回明文再测(否则会
fail to load ApplicationContext
)
1.打印版单测
package com.imooc;
import org.junit.jupiter.api.Test;
/**
*
*/
public class LoggerTest {
@Test
public void test1() {
System.out.println("=========");
}
}
2
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Logger2Test {
// 选择org.slf4j下的接口
private final Logger logger = LoggerFactory.getLogger(Logger2Test.class);
@Test
public void test1() {
logger.info("info...");
}
}
2.测试DAO层(JPA)
版本:
junit5
springboot-2.7.2` 不启动应用 数据库已配
目录:
1.@Repository
注解
2.@DataJpaTest
注解
3.@AutoConfigureTestDatabase
注解
依赖
spring-boot-starter-web (2.7.2)
spring-boot-starter-test (with junit5)
mysql-connector-java (8.0)
spring-boot-starter-data-jpa
h2 # 构建基于内存的数据库环境
@Repository
public interface ProductCategoryRepository extends JpaRepository<ProductCategory, Integer> {
}
2.@DataJpaTest
可以在springboot
的环境只测JPA
组件,它会默认扫描@Entity
和@Repository
注解
3.@AutoConfigureTestDatabase
会自动配置一个基于内存的数据库,只要依赖中含有一个可用的基于内存的嵌入式数据库。
结果会自动回滚,不会发生数据库变化。若使用实际数据库可设置 replace值为Replace.NONE
最终元素(已验证)
/
@Data
@Entity // JPA
public class ProductCategory implements Serializable {
// ...
}
/
@Repository
public interface ProductCategoryRepository extends JpaRepository<ProductCategory, Integer> {
}
/
@DataJpaTest // 只启动JPA组件不启动全环境
@AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE) // 创建一个基于内存的数据库环境
class ProductCategoryRepositoryTest {
@Autowired
ProductCategoryRepository repository;
@Test
public void testFindById() {
Optional<ProductCategory> byId = repository.findById(1);
System.out.println("查询结果:");
System.out.println(byId);
}
}
控制台
查询结果:
Optional[ProductCategory(categoryId=1, categoryType=1, categoryName=热销榜, createTime=2022-08-03 06:37:48.0, updateTime=2022-08-03 06:37:48.0)]
参考资料:
(方法讲解)https://howtodoinjava.com/spring-boot2/testing/datajpatest-annotation/#1-repository-annotation
(实际代码)https://github.com/lokeshgupta1981/jakarta-projects/tree/master/spring-boot-projects/hibernate-examples
2.测试DAO层(Mybatis)
版本:
junit5
不启动应用 数据库已配 单测在主模块里
目录:
1.@Mapper
注解
2.@MybatisTest
注解
3.@AutoConfigureTestDatabase
注解
依赖(+)
mybatis-spring-boot-starter-test(@MybatisTest)
h2
@MybatisTest
最终元素(已验证)
///子模块
@Mapper
public interface LoginMapper {
@Select("SELECT * FROM t_user")
List<User> selectAllUser();
}
///main模块
@MybatisTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class LoginMapperTest {
@Autowired
LoginMapper loginMapper;
@Test
void contextLoads() {
List<User> users = loginMapper.selectAllUser();
System.out.println("查询所有用户:");
System.out.println(users);
}
}
控制台
查询所有用户:
[User(uid=1, uname=123, upwd=password, pwdErr=null), User(uid=2, uname=test, upwd=test, pwdErr=null), User(uid=3, uname=234, upwd=password, pwdErr=null), User(uid=4, uname=234, upwd=password, pwdErr=null), User(uid=5, uname=2345, upwd=password, pwdErr=null), User(uid=6, uname=452345, upwd=password, pwdErr=null), User(uid=7, uname=523, upwd=password, pwdErr=null), User(uid=8, uname=453, upwd=password, pwdErr=null), User(uid=9, uname=234523, upwd=password, pwdErr=null), User(uid=10, uname=45, upwd=password, pwdErr=null), User(uid=11, uname=452345, upwd=password, pwdErr=null), User(uid=12, uname=2345, upwd=password, pwdErr=null)]
参考资料:
其它:默认回滚机制
单测默认会自动回滚,如果执行有插入或更新的数据,数据库的数据不会变化。且假若新增/更新数据没设置【非null】字段,单测也一样会通过(可以理解为执行错了随后回滚了?!)
若想写入数据库,禁止回滚,重写@Rollback
注解,将value
值置为false
。
[2022-08-03 20:52:06]
@DataJpaTest // 只启动JPA组件不启动全环境
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) // 创建一个基于内存的数据库环境
@Rollback(value = false) // 不自动回滚,真实写入数据库
class ProductCategoryRepositoryTest {
@Autowired
ProductCategoryRepository repository;
@Test
public void testSave() {
ProductCategory category = new ProductCategory();
System.out.println("插入ing");
category.setCategoryId(2);
category.setCategoryType(2);
category.setCategoryName("女生最爱");
category.setCreateTime(new Date());
category.setUpdateTime(new Date());
repository.save(category);
System.out.println("插入一条数据");
Optional<ProductCategory> byId = repository.findById(2);
System.out.println("插入后查询:" + byId);
}
}
控制台
此时真正读写数据库,当插入not null字段时,则会触发ConstraintViolationException
(约束违背异常)
否则执行后,此时,数据库数据写入成功。
附:多模块工程的单测
多模块工程:
如果只有一个模板,以上方式都可以;
如果是多模块文件,目标文件可以放子模块(已配父子模块关系),但是单测建议放main
模块,否则会抛异常
【Test ignored.
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
·】
[2022-08-03 11:16:49] mybatis
目标代码放子模块,单测当主模块√
[2022-08-03 11:16:49] jpa
目标代码放子模块,单测当主模块×(都放主模块 单测√)
附:spring1.x junit4 的测试
Repository接口的@Repository
注解可写可不写
Test类的必要注解:2个
@RunWith(SpringRunner.class) // 启动容器环境
@SpringBootTest
class ProductCategoryRepositoryTest {
ProductCategoryRepository repository;
@Test
public void testFindById() {
Optional<ProductCategory> byId = repository.findById(1);
System.out.println("查询结果:");
System.out.println(byId);
}
}
其它:
IDEA中在目标类内部使用快捷键[Ctrl+Alt+T]快速生成测试类