Spring Boot 2 实践记录之 封装依赖及尽可能不创建静态方法以避免在 Service 和 Controller 的单元测试中使用 Powermock
在前面的文章中(Spring Boot 2 实践记录之 Powermock 和 SpringBootTest)提到了使用 Powermock 结合 SpringBootTest、WebMvcTest 来 Mock Service、Controller 中的 静态类和静态方法。
但此法有两个弊端,一是这样的单元测试运行速度慢,二是时不时会出现测试运行停顿的情况。
一个可选的方案就是将这些用在 Service、Controller 中的静态类和静态方法的引用,封装在普通 Bean 中,Service、Controller 使用这些 Bean 来完成相应的功能。这样一来,针对 Service、Controller 的单元测试中,就可以使用 @MockBean 结合 Mockito 直接 Mock 这些封装类及其方法了。
例如,在用户注册中,使用了 UUID 类来生成 用户id,使用 Date 插入注册时间,代码如下:
@Service
public class UsersServiceImpl implements UsersServiceInterface { @Autowired
private Users users; @Autowired
private UsersMapper usersMapper; /**
* 用户注册 service 方法
* @param userIn
* @return
*/
@Override
public String signUp(UserIn userIn) {
String result;
Date now = new Date();
users.setUserId(UUID.randomUUID().toString());
users.setRegTime(now);
...... try {
Integer result = usersMapper.insert(users);
if (0 == result) {
result = "fail";
} else {
result = "success";
} catch (Exception e) {
log.error(e.getLocalizedMessage(), e.fillInStackTrace());
result = "fail";
} finally {
return result;
}
}
}
对应的单元测试:
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*"})
@PrepareForTest({UsersService.class, Date.class, UUID.class})
@SpringBootTest
@Transactional
public class UsersServiceMybatisImplTest { @Autowired
private UsersServiceMybatisImpl usersServiceMybatis; @MockBean
private EncryptInterface encryptInterface; @MockBean
private DateUtils dateUtils; @Autowired
private UsersMapper usersMapper; private UserIn userIn;
@Before
public void setUp() throws Exception {
userIn = new UserIn();
Mockito.when(encryptInterface.passwordGenerator("hello123")).thenReturn("abcdefghijklmn");
} @After
public void tearDown() throws Exception {
} @Test
public void signUp(){
Date date = (new GregorianCalendar(2018, 11, 9)).getTime();
PowerMockito.mockStatic(Date.class);
PowerMockito.whenNew(Date.class).withNoArgments().thenReturn(date);
String randomString = "abcdefg";
UUID uuid = PowerMockito.mock(UUID.class);
Mockito.when(uuid.toString()).thenReturn(randomString);
PowerMockito.mockStatic(UUID.class);
PowerMockito.when(UUID.randomUUID()).thenReturn(uuid);
userIn.setUserId("admin123");
userIn.setSign("盘古氏");
userIn.setEmail("pangu@gushen.com");
userIn.setPassword("hello123");
userIn.setRePassword("hello123");
userIn.setIp("127.0.0.1");
userIn.setNick("盘古");
userIn.setSchool("混沌大学");
assertEquals("success", result);
Users user = usersMapper.selectByPrimaryKey("abcdefg");
assertEquals(date.toString(), user.getRegTime().toString());
......
} }
将静态类和静态方法封装成普通 Bean的示例如下:
工具类:
@Component
public class DateUtils {
public Date generateDate() {
return new Date();
}
}
@Component
public class UUIDUtils {
public Date generateUUID() {
return UUID.randomUUID();
}
}
Service 类:
@Service
public class UsersServiceImpl implements UsersServiceInterface { @Autowired
private Users users; @Autowired
private UsersMapper usersMapper; @Autowired
private DateUtils dateUtils; @Autowired
private UUIDUtils uuidUtils; /**
* 用户注册 service 方法
* @param userIn
* @return
*/
@Override
public String signUp(UserIn userIn) {
String result;
Date now = dateUtils.generateDate();
users.setUserId(uuidUtils.generateUUID().toString());
users.setRegTime(now);
...... try {
Integer result = usersMapper.insert(users);
if (0 == result) {
result = "fail";
} else {
result = "success";
} catch (Exception e) {
log.error(e.getLocalizedMessage(), e.fillInStackTrace());
result = "fail";
} finally {
return result;
}
}
}
单元测试:
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class UsersServiceMybatisImplTest { @Autowired
private UsersServiceMybatisImpl usersServiceMybatis; @MockBean
private EncryptInterface encryptInterface; @MockBean
private DateUtils dateUtils; @MockBean
private UUIDUtils uuidUtils; @Autowired
private UsersMapper usersMapper; private UserIn userIn; @Before
public void setUp() throws Exception {
userIn = new UserIn();
Mockito.when(encryptInterface.passwordGenerator("hello123")).thenReturn("abcdefghijklmn");
} @After
public void tearDown() throws Exception {
} @Test
public void signUp(){
Date date = (new GregorianCalendar(2018, 11, 9)).getTime();
Mockito.when(dateUtils.generateDate()).thenReturn(date);
UUID uuid = Mockito.mock(UUID.randomUUID());
Mockito.when(uuid.toString()).thenReturn("abcdefg");
Mockito.when(uuidUtils.generateUUID()).thenReturn(uuid);
userIn.setUserId("admin123");
userIn.setSign("盘古氏");
userIn.setEmail("pangu@gushen.com");
userIn.setPassword("hello123");
userIn.setRePassword("hello123");
userIn.setIp("127.0.0.1");
userIn.setNick("盘古");
userIn.setSchool("混沌大学");
assertEquals("success", result);
Users user = usersMapper.selectByPrimaryKey("abcdefg");
assertEquals(date.toString(), user.getRegTime().toString());
......
}
Spring Boot 2 实践记录之 封装依赖及尽可能不创建静态方法以避免在 Service 和 Controller 的单元测试中使用 Powermock的更多相关文章
- Spring Boot 2 实践记录之 使用 ConfigurationProperties 注解将配置属性匹配至配置类的属性
在 Spring Boot 2 实践记录之 条件装配 一文中,曾经使用 Condition 类的 ConditionContext 参数获取了配置文件中的配置属性.但那是因为 Spring 提供了将上 ...
- Spring Boot 2 实践记录之 MyBatis 集成的启动时警告信息问题
按笔者 Spring Boot 2 实践记录之 MySQL + MyBatis 配置 中的方式,如果想正确运行,需要在 Mapper 类上添加 @Mapper 注解. 但是加入此注解之后,启动时会出现 ...
- Spring Boot 2 实践记录之 Redis 及 Session Redis 配置
先说 Redis 的配置,在一些网上资料中,Spring Boot 的 Redis 除了添加依赖外,还要使用 XML 或 Java 配置文件做些配置,不过经过实践并不需要. 先在 pom 文件中添加 ...
- Spring Boot 2 实践记录之 Powermock 和 SpringBootTest
由于要代码中使用了 Date 类生成实时时间,单元测试中需要 Mock Date 的构造方法,以预设其行为,这就要使用到 PowerMock 在 Spring Boot 的测试套件中,需要添加 @Ru ...
- Spring Boot 2 实践记录之 使用 Powermock、Mockito 对 UUID 进行 mock 单元测试
由于注册时,需要对输入的密码进行加密,使用到了 UUID.sha1.md 等算法.在单元测试时,使用到了 Powermock,记录如下. 先看下加密算法: import org.apache.comm ...
- Spring Boot 2 实践记录之 MySQL + MyBatis 配置
如果不需要连接池,那么只需要简单的在pom文件中,添加mysql依赖: <dependency> <groupId>mysql</groupId> <arti ...
- Spring Boot 2 实践记录之 组合注解原理
Spring 的组合注解功能,网上有很多文章介绍,不过都是介绍其使用方法,鲜有其原理解析. 组合注解并非 Java 的原生能力.就是说,想通过用「注解A」来注解「注解B」,再用「注解B」 来注解 C( ...
- Spring Boot 2 实践记录之 条件装配
实验项目是想要使用多种数据库访问方式,比如 JPA 和 MyBatis. 项目的 Service 层业务逻辑相同,只是具体实现代码不同,自然是一组接口,两组实现类的架构比较合理. 不过这种模式却有一个 ...
- Spring Boot 之日志记录
Spring Boot 之日志记录 Spring Boot 支持集成 Java 世界主流的日志库. 如果对于 Java 日志库不熟悉,可以参考:细说 Java 主流日志工具库 关键词: log4j, ...
随机推荐
- 慕课网access_token的获取(下)
接口调用返回的结果是两个字段:access_token和expires_in,所以需要创建一个实体类封装这两个字段 运行测试类WeixinTest.java控制台打印出错误信息 重置开发者密钥试试看 ...
- eclipse搭建struts2环境及所遇到的问题
最近几天一直在搭建struts2框架,本身struts2框架的搭建是非常简单的,但不知道为什么最近就是总是报错,报了一大串的错 首先就是每次在类的根路径下创建struts.xml时,就报错,也不知道为 ...
- sibling
sibling 英 ['sɪblɪŋ] 美 ['sɪblɪŋ] 名词. 兄,弟,姐,妹网络. 兄弟,兄弟姐妹,同胞变形. 复数:siblings
- In case of failure
In case of failure http://acm.hdu.edu.cn/showproblem.php?pid=2966 Time Limit: 60000/30000 MS (Java/O ...
- day12:vcp考试
Q221. An administrator is creating a new Platform Service Controller Password Policy with the follow ...
- js-addEventListener()第三个参数useCapture
概述: 第3个参数叫做useCapture,是一個boolean值,就是true or false .如果送出true的話就是瀏覽器會使用Capture方式,false的話是Bubbling,只有在特 ...
- Spring的3.0提供了一种:SpEL注入方式(了解)
1. SpEL:Spring Expression Language是Spring的表达式语言,有一些自己的语法 2. 语法 * #{SpEL} 3. 例如如下的代码 <!-- SpEL的方式 ...
- To set Nginx Upload Size For “413–Request Entity Too Large” Error
Modify NGINX Configuration File sudo nano /etc/nginx/nginx.conf Search for this variable: client_max ...
- 共享内存system v(未编译)
#include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> ...
- 20155317 王新玮 2016-2017-2 《Java程序设计》第9周学习总结
20155317 王新玮 2016-2017-2 <Java程序设计>第9周学习总结 教材学习内容总结 数据库本身是个独立运行的应用程序 撰写应用程序是利用通信协议对数据库进行指令交换,以 ...