官方文档
javaapi:https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
官网:https://site.mockito.org/
github:https://github.com/mockito/mockito
如何编写一个单元测试用例
https://www.vogella.com/tutorials/Mockito/article.html#mockitousage
如何编写一个集成测试用例
这个不同框架不同,可以参考spring boot的写法
如何mock static的方法?
https://asolntsev.github.io/en/2020/07/11/mockito-static-methods/
如何不启动spring整体工程,在本地实际连db测试dao层代码?
方法思路:
- 采用jdbc 方式直连
- 采用反射机制 动态 实例化类 及其属性
mybatis sqlSession相关解释见 https://www.yuque.com/antone/zv3ypu/tl15md
@Slf4j
public class MutiDataSourceTest {
private static final Logger LOGGER = LoggerFactory.getLogger(MutiDataSourceTest.class);
private static Map<DataSourceType, DataSource> dataSourceContext = new HashMap<>();
//@Getter
private static Map<DataSourceType, SqlSessionFactory> sqlSessionFactoryContext = new HashMap<>();
private static Map<DataSourceType, Properties> dataSourceTypeToConfig = new HashMap<>();
private static Map<Class<? extends Annotation>, DataSourceType> classToDataSourceType = new HashMap<>();
private static List<SqlSession> sqlSessions = new ArrayList<>();
public void logObject(Object o) {
//LOGGER.info("obj:{}", o);
}
static {
classToDataSourceType.put(EXPLORER.class, DataSourceType.EXPLORE);
// 数据库配置信息
Properties explorerConfig = new Properties();
explorerConfig.put("driver", "com.mysql.jdbc.Driver");
explorerConfig.put("url",
"jdbc:mysql://xxxx:3306/cheetah?useUnicode=true&characterEncoding=utf8"
+ "&rewriteBatchedStatements=true");
explorerConfig.put("username", "xxx");
explorerConfig.put("password", "xxx");
LoggerUtil.info(LOGGER, "adb config:{0}", explorerConfig);
dataSourceTypeToConfig.put(DataSourceType.EXPLORE, explorerConfig);
}
public static enum DataSourceType {
EXPLORE
}
public static SqlSession openSession(DataSourceType dataSourceType) {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactoryByType(dataSourceType);
SqlSession sqlSession = sqlSessionFactory.openSession(null, true);
sqlSessions.add(sqlSession);
return sqlSession;
}
public static <T> T getMapper(Class<T> tClass) {
DataSourceType dataSourceType = parseType(tClass);
SqlSessionFactory sqlSessionFactory = getSqlSessionFactoryByType(dataSourceType);
MapperRegistry mapperRegistry = sqlSessionFactory.getConfiguration().getMapperRegistry();
if (!mapperRegistry.hasMapper(tClass)) {
sqlSessionFactory.getConfiguration().addMapper(tClass);
}
SqlSession sqlSession = openSession(dataSourceType);
return sqlSession.getMapper(tClass);
}
public static SqlSessionFactory getSqlSessionFactoryByType(DataSourceType dataSourceType) {
if (!sqlSessionFactoryContext.containsKey(dataSourceType)) {
DataSource dataSource = getDataSourceByType(dataSourceType);
Configuration configuration = new Configuration();
JdbcTransactionFactory jdbcTransactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("test", jdbcTransactionFactory, dataSource);
configuration.setEnvironment(environment);
configuration.getTypeAliasRegistry().registerAliases("com.alibaba.aliexpress.module");
configuration.setMapUnderscoreToCamelCase(true);
MybatisProperties mybatisProperties = new MybatisProperties();
mybatisProperties.setMapperLocations(
new String[] {"classpath*:com/alipay/xxxx/dal/xxx/mapper/*.xml"}); //这里是mapper配置的地址
Resource[] resources = mybatisProperties.resolveMapperLocations();
for (Resource mapperLocation : resources) {
XMLMapperBuilder xmlMapperBuilder = null;
try {
xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
configuration, mapperLocation.toString(), configuration.getSqlFragments());
} catch (IOException e) {
e.printStackTrace();
}
xmlMapperBuilder.parse();
}
DefaultSqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory(configuration);
//LOGGER.info("{} sqlSessionFactory init success.", dataSourceType);
sqlSessionFactoryContext.put(dataSourceType, sqlSessionFactory);
//addIntercepter(sqlSessionFactory, dataSourceType);
}
return sqlSessionFactoryContext.get(dataSourceType);
}
public static DataSource getDataSourceByType(DataSourceType dataSourceType) {
if (!dataSourceContext.containsKey(dataSourceType)) {
DataSource dataSource = buildDataSouce(dataSourceType);
dataSourceContext.put(dataSourceType, dataSource);
//LOGGER.info("{} dataSource init success.", dataSourceType);
}
return dataSourceContext.get(dataSourceType);
}
private static DataSource buildDataSouce(DataSourceType dataSourceType) {
Properties properties = dataSourceTypeToConfig.get(dataSourceType);
UnpooledDataSource dataSource = new UnpooledDataSource();
dataSource.setDriver(properties.getProperty("driver"));
dataSource.setUrl(properties.getProperty("url"));
dataSource.setUsername(properties.getProperty("username"));
dataSource.setPassword(properties.getProperty("password"));
return dataSource;
}
private static <T> DataSourceType parseType(Class<T> tClass) {
Set<Class<? extends Annotation>> classes = classToDataSourceType.keySet();
for (Class<? extends Annotation> anotationClass : classes) {
if (anotationClass == Mapper.class) {
continue;
}
if (tClass.isAnnotationPresent(anotationClass)) {
return classToDataSourceType.get(anotationClass);
}
}
//return DataSourceType.TDDL;
return null;
}
@AfterClass
public static void destroy() {
sqlSessions.forEach(s -> {
if (s != null) {
s.close();
}
});
}
}
public class ServiceTest extends MutiDataSourceTest {
private static final Logger logger = LoggerFactory.getLogger(ServiceTest.class);
private boolean added;
@Before
public void serviceTestInit() {
beforeInit();
populateField(this);
//afterPopulate(this);
}
private void beforeInit() {
addIntercepter();
}
public <T> T createService(Class<T> tClass) {
return (T)createObject(tClass);
}
private Object createObject(Class tClass) {
try {
//log.debug("create instance for class:{}", tClass.getName());
Class c = findImplClass(tClass);
if (c == null) {
return null;
}
Object o = c.newInstance();
populateField(o);
//afterPopulate(o);
return o;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void afterPopulate(Object o) {
//if (o instanceof BaseServiceImpl) {
// try {
// initBaseImpl(o);
// } catch (InvocationTargetException e) {
// e.printStackTrace();
// } catch (IllegalAccessException e) {
// e.printStackTrace();
// }
//}
}
private void populateField(Object o) {
Field[] declaredFields = o.getClass().getDeclaredFields();
Arrays.stream(declaredFields).filter(
field -> field.isAnnotationPresent(Autowired.class) || field.isAnnotationPresent(
Resource.class)).forEach(f -> populateField(f, o));
}
private <T> Class findImplClass(Class<T> tClass) {
if (tClass.isInterface()) {
String className = tClass.getSimpleName() + "Impl";
String packageName = tClass.getName().replace(tClass.getSimpleName(), "impl.");
String implClassName = packageName + className;
//String implClassName2 = packageName + className2;
//log.debug("find impl class for:{} is {}", tClass.getName(), implClassName);
Class<?> aClass = null;
try {
aClass = Class.forName(implClassName);
} catch (ClassNotFoundException e) {
LoggerUtil.warn(logger, "not found impl class for:{0},skip create instance", tClass.getName());
// e.printStackTrace();
}
return aClass;
}
return tClass;
}
@SneakyThrows
private void populateField(Field field, Object target) {
Class<?> declaringClass = field.getType();
LoggerUtil.debug(logger, "field class:{0}", declaringClass);
Object fieldValue = null;
if (declaringClass.getName().contains("Service")) {
fieldValue = createService(declaringClass);
} else if ((declaringClass.isAnnotationPresent(EXPLORER.class))) {
fieldValue = super.getMapper(declaringClass);
} else {
fieldValue = createObject(declaringClass);
}
field.setAccessible(true);
field.set(target, fieldValue);
LoggerUtil.info(logger, "inject field:{0} value:{1}", field.getName(), fieldValue);
}
private void addIntercepter() {
if (this.added) {
return;
}
for (DataSourceType dataSourceType : DataSourceType.values()) {
getSqlSessionFactoryByType(dataSourceType);
}
//Map<DataSourceType, SqlSessionFactory> sqlSessionFactoryContext = getSqlSessionFactoryContext();
//for (Entry<DataSourceType, SqlSessionFactory> entry : sqlSessionFactoryContext.entrySet()) {
// SqlSessionFactory sqlSessionFactory = entry.getValue();
// DataSourceType dataSourceType = entry.getKey();
// PageInterceptor interceptor = new PageInterceptor();
// Properties properties = new Properties();
// properties.put("helperDialect", "mysql");
// properties.put("reasonable", "true");
// properties.put("supportMethodsArguments", "true");
// properties.put("params", "count=countSql;pageNum=pageNumber;pageSize=pageSize;");
// interceptor.setProperties(properties);
// sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
// if (dataSourceType == DataSourceType.ADB) {
// PartitionParamInterceptor partitionParamInterceptor = new PartitionParamInterceptor();
// partitionParamInterceptor.setPartitionService(createService(PartitionService.class));
// sqlSessionFactory.getConfiguration().addInterceptor(partitionParamInterceptor);
// }
//}
this.added = true;
}
}
测试类只需要继承ServiceTest即可