公司用的 nacos 做服务管理,还是 1.4 的老版本,同时还有一些老项目没接 nacos 直接走 http 请求,测试目前有一套自研的 mock 工具,但是对代码有一些侵入,而且有些项目存在依赖不兼容问题。
所以现在想一步到位在 ng 层面做 mock 解决所有问题,请教下各位大佬有没有开源的 mock 框架,或者有没有其他好的解决方案。
顺便就分享下现用的 mock 工具,原理就是在被 mock 类上加注解,然后通过反射替换返回值或者请求到 mock 服务上。
主要实现 2 个功能:
领导觉得太 low 了让在 ng 层实现,所以希望有能在 ng 层实现上面俩功能的工具,求大佬们推荐。
@Aspect
public class ConfMockAspect {
@Autowired
SpelExcetor spelExcetor;
private final static Logger logger = LoggerFactory.getLogger(ConfMockAspect.class);
private static String mock_system_test_url = "http://xxxx";
private static String mock_system_dev_url = "http://xxxx";
@Pointcut("@within(com.mock.ConfMock)")
private void aspect() {}
@Around("aspect()")
public Object around(JoinPoint joinPoint) throws Throwable {
Object target = joinPoint.getTarget();
Class<?> targetClass = target.getClass();
Class<?>[] interfaces = targetClass.getInterfaces();
String sName = targetClass.getSimpleName();
MethodSignature sig = (MethodSignature)joinPoint.getSignature();
Method method = sig.getMethod();
String methodName = method.getName();
Type type = method.getGenericReturnType();
String key = "ConfMock." + sName + "." + methodName;
// 走mock系统
String sysKey1 = "system.ConfMock." + sName;
String sysKey2 = "system.ConfMock." + sName + "." + methodName;
String value = null;
if (LocalCacheRepository.getInstance().get(sysKey1) != null
|| LocalCacheRepository.getInstance().get(sysKey2) != null) {
String url = null;
if (PropertyConstant.CONF_PROD_DEV.equals(AppInstance.getEnv())) {
url = mock_system_dev_url + String.format("/api?className=%s&method=%s¶mClass=%s",
interfaces[0].getName(), methodName, method.getParameterTypes()[0].getName());
} else if (PropertyConstant.CONF_PROD_TEST.equals(AppInstance.getEnv())){
url = mock_system_test_url + String.format("/api?className=%s&method=%s¶mClass=%s",
interfaces[0].getName(), methodName, method.getParameterTypes()[0].getName());
} else {
url = mock_system_uat_url + String.format("/api?className=%s&method=%s¶mClass=%s",
interfaces[0].getName(), methodName, method.getParameterTypes()[0].getName());
}
String param = JSON.toJSONString(joinPoint.getArgs()[0], new LengthFilter());
value = HttpUtil.doPost(param, new HashMap<>(), url);
if (value != null) {
return JSON.parseObject(value, type);
}
} else {
value = getValue(joinPoint, key);
if (value != null) {
Object result = parseReturn(value, type, joinPoint.getArgs());
return result;
}
}
return ((ProceedingJoinPoint)joinPoint).proceed();
}
private String getValue(JoinPoint joinPoint, String key) {
try {
Properties properties = LocalCacheRepository.getInstance().getProperties();
Set<Object> set = properties.keySet();
for (Object srt : set) {
String keyStr = srt.toString();
if (keyStr.startsWith(key)) {
String s = org.apache.commons.lang3.StringUtils.removeStart(keyStr, key);
if (!StringUtils.isEmpty(s)) {
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setRootObject(joinPoint.getArgs());
Boolean result =
(Boolean)parser.parseExpression(org.apache.commons.lang3.StringUtils.removeStart(s, "."))
.getValue(context);
if (result) {
return properties.getProperty(keyStr);
}
}
}
}
if (properties.containsKey(key)) {
return properties.getProperty(key);
}
} catch (Exception e) {
logger.warn("解析key失败", e);
}
return null;
}
private Object parseReturn(String value, Type type, Object[] args) {
if (String.class.getTypeName().equals(type.getTypeName())) {
return value;
}
Object object = JSON.parse(value);
if (object instanceof JSONArray) {
JSONArray array = (JSONArray)object;
parseValue(array, args);
return array.toJavaObject(type);
} else if (object instanceof JSONObject) {
JSONObject jsonObject = (JSONObject)object;
parseValue(jsonObject, args);
return jsonObject.toJavaObject(type);
}
return object;
}
private void parseValue(JSONArray array, Object rootObject) {
if (array != null && !array.isEmpty()) {
for (int i = 0; i < array.size(); i++) {
Object value = array.get(i);
if (value != null) {
if (value instanceof String) {
Object newValue = doneInSpringContext((String)value, rootObject);
if (newValue != null) {
array.set(i, newValue);
}
} else if (value instanceof JSONObject) {
parseValue((JSONObject)value, rootObject);
} else if (value instanceof JSONArray) {
parseValue((JSONArray)value, rootObject);
}
}
}
}
}
private void parseValue(JSONObject object, Object rootObject) {
Set<String> set = object.keySet();
if (!set.isEmpty()) {
for (String key : set) {
Object value = object.get(key);
if (value != null) {
if (value instanceof String) {
if (isSpel((String)value)) {
Object newValue = doneInSpringContext(spelValue((String)value), rootObject);
if (newValue != null) {
object.put(key, newValue);
}
}
} else if (value instanceof JSONObject) {
parseValue((JSONObject)value, rootObject);
} else if (value instanceof JSONArray) {
parseValue((JSONArray)value, rootObject);
}
}
}
}
}
private static boolean isSpel(String value) {
// ${}
if (value != null && value.startsWith("${") && value.endsWith("}")) {
return true;
}
return false;
}
public static String spelValue(String value) {
if (isSpel(value)) {
value = org.apache.commons.lang3.StringUtils.removeFirst(value, "\\$\\{");
value = org.apache.commons.lang3.StringUtils.removeEnd(value, "}");
return value;
}
return value;
}
private Object doneInSpringContext(String value, Object rootObject) {
try {
return spelExcetor.doneInSpringContext(null, rootObject, value);
} catch (Exception e) {
}
return null;
}
public static class LengthFilter implements ValueFilter{
@Override
public Object process(Object object, String name, Object value) {
if (value != null && value instanceof String) {
String var = (String)value;
if (var.length() > 500) {
return var.substring(0, 500);
}
}
return value;
}
}