网站首页 > 技术文章 正文
背景
mybatis-plus作为mybatis的增强工具,在使用过程中简化开发,大大得提高了工作效率。mybatis-plus提供了一套通用的mapper和service操作,对于单表操作很方便,但是在写单元测试的时候还是存在有很多不同于mybatis的地方。本文介绍本人在开发过程当中遇到的一些坑和自己的理解。
Mock是在测试过程中,对于一些不容易构造的对象,创建一个mock对象来模拟对象的行为。比如说当写单元测试不想调用数据库时,就可以在调用mapper的方法时使用Mock打桩,mock想要返回的结果。
依赖引用
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.23.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4-rule</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
Service
@Service
public class TestServiceImpl extends ServiceImpl<TestMapper, UserInfo> implements TestService {
@Override
public boolean insert(UserInfo userInfo) {
return this.save(userInfo);
}
@Override
public boolean insertList(List<UserInfo> list) {
return this.saveBatch(list, 1000);
}
}
单元测试
首先对单个插入进行单元测试,通过分析mybatis-plus自带的ServiceImpl,发现save方法调用的Mapper的insert方法
default boolean save(T entity) {
return SqlHelper.retBool(this.getBaseMapper().insert(entity));
}
单元测试代码如下:
@RunWith(PowerMockRunner.class)
@SpringBootTest
public class TestServiceImplTest {
@InjectMocks
private TestServiceImpl testService;
@Mock
private TestMapper testMapper;
@Test
public void testInsert() {
UserInfo userInfo = new UserInfo();
userInfo.setId(1);
userInfo.setName("张三");
//对mapper的insert打桩,返回成功标识1
PowerMockito.when(testMapper.insert(userInfo)).thenReturn(1);
Assert.assertTrue(testService.insert(userInfo));
}
}
单个插入的单元测试就很简单,但是通过分析批量插入的saveBatch方法发现没有通过Mapper,而是直接在service层实现的,这时该在哪个方法上打桩?有没有办法直接在saveBatch方法上打桩?
public boolean saveBatch(Collection<T> entityList, int batchSize) {
String sqlStatement = this.sqlStatement(SqlMethod.INSERT_ONE);
return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> {
sqlSession.insert(sqlStatement, entity);
});
}
protected <E> boolean executeBatch(Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
Assert.isFalse(batchSize < 1, "batchSize must not be less than one", new Object[0]);
return !CollectionUtils.isEmpty(list) && this.executeBatch((sqlSession) -> {
int size = list.size();
int i = 1;
for(Iterator var6 = list.iterator(); var6.hasNext(); ++i) {
E element = var6.next();
consumer.accept(sqlSession, element);
if (i % batchSize == 0 || i == size) {
sqlSession.flushStatements();
}
}
});
}
首先,尝试直接在Mock对象TestServiceImpl的saveBatch方法上打桩,结果直接报错,无法运行
@Test
public void testInsertList() {
PowerMockito.when(testService.saveBatch(Mockito.anyList())).thenReturn(true);
List<UserInfo> list = new ArrayList<>();
UserInfo userInfo = new UserInfo();
userInfo.setId(1);
userInfo.setName("张三");
list.add(userInfo);
Assert.assertTrue(testService.insertList(list));
}
Mockito.spy()可以在真实对象上创建间谍(类似于浅克隆),尝试在创建的间谍对象上打桩
@Test
public void testInsertList() {
//创建spy间谍对象
TestService spy = Mockito.spy(testService);
PowerMockito.doReturn(true).when(spy).saveBatch(Mockito.anyList());
List<UserInfo> list = new ArrayList<>();
UserInfo userInfo = new UserInfo();
userInfo.setId(1);
userInfo.setName("张三");
list.add(userInfo);
//特别注意,spy对象和testService对象是两个不同的对象,一定要调用spy对象的insertList方法
Assert.assertTrue(spy.insertList(list));
}
测试结果通过,完美解决Mybatis-plus批量插入的单元测试
- 上一篇: 年终奖10w的同事,写的代码那叫一个优雅!
- 下一篇: Map的几种遍历方式 map的三种遍历方式js
猜你喜欢
- 2024-12-18 Java开发中MongoDB数据库相关操作
- 2024-12-18 HashMap有几种遍历方法?推荐使用哪种?
- 2024-12-18 在RedisTemplate中使用scan代替keys指令
- 2024-12-18 MQ的发布订阅模式(fanout) mq几种消息模式
- 2024-12-18 Mybatis参数-ParameterMapping处理参数
- 2024-12-18 既然有MySQL了,为什么还要有MongoDB?
- 2024-12-18 Java遍历一个 List 有哪些方式?每种的实现原理以及哪种最高效?
- 2024-12-18 为什么很多人不愿意用hibernate了?
- 2024-12-18 Qt中 QMap 类、QHash 类、QVector 类详解
- 2024-12-18 半小时搞懂 IO 模型 io模型详解
- 最近发表
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (84)
- el-date-picker开始日期早于结束日期 (76)
- js判断是否是json字符串 (75)
- c语言min函数头文件 (77)
- asynccallback (87)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 无效的列索引 (74)