1. 如果配置mock測試為真,傳回mock資料,為假,傳回真實資料
2. 實作方式
可以每次在方法中判斷,但是很麻煩,好多if判斷
可以定義接口,多一個mock實作,在程式啟動的時候,隻加載mock實作類,真實實作類不加載(可以自定義類加載器或者使用spring bean加載過濾)
也可以使用AOP切面,判斷是否mock看情況傳回
其他實作方式暫時沒有想法或者頭緒
最後确定使用AOP簡單快捷
3. 代碼
自定義注解
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MockData {
@AliasFor("method")
String value() default "";
/**
* 是否開啟mock資料傳回
*/
boolean isOpen() default true;
/**
* 指定mock資料組裝 <strong>無參</strong>方法
*/
@AliasFor("value")
String method() default "";
/**
* mock方法類,預設目前類
* class數組有且隻能有一個class,該類最好使用spring bean管理
*/
Class<?>[] classFor() default {};
}
AOP 切面
@Slf4j
@Aspect
@Component
public class MockAspect {
@Value("${mockModal}")
private boolean mockModal;
@Autowired
private BeanFactory beanFactory;
/**
* mock資料切面方法
*
* @param joinPoint
* @param mockData
*/
@Around("within(@org.springframework.stereotype.Service *) && @annotation(mockData)")
public Object around(ProceedingJoinPoint joinPoint, MockData mockData) {
Object res = Res.fail("服務内部mock資料錯誤!");
try {
// 判斷是否開啟了 mock 資料傳回
if (mockData.isOpen() && mockModal) {
// @AliasFor 是spring 特有注解,這裡使用spring提供的工具類擷取注解,要不然 value和method互替不會生效
mockData = AnnotationUtils.getAnnotation(mockData, MockData.class);
assert mockData != null;
Object bean;
Method[] methods;
if (mockData.classFor().length == 0) {
// 預設使用目前類
bean = beanFactory.getBean(joinPoint.getTarget().getClass());
methods = joinPoint.getTarget().getClass().getDeclaredMethods();
} else {
try {
bean = beanFactory.getBean(mockData.classFor()[0]);
} catch (NoSuchBeanDefinitionException e) {
log.warn("mock資料通路類不在spring bean工廠中改用反射方式...");
bean = mockData.classFor()[0].newInstance();
}
methods = mockData.classFor()[0].getDeclaredMethods();
}
// mock 注解指定的 mock方法名
String name = mockData.method();
Optional<Method> check = Arrays.stream(methods).filter(method -> method.getName().equals(name)).findFirst();
if (check.isPresent()) {
Method method = check.get();
method.setAccessible(true);
// 執行 mock 方法
res = method.invoke(bean);
}
} else {
res = joinPoint.proceed();
}
} catch (Throwable throwable) {
log.error("mock資料切面出錯!", throwable);
}
return res;
}
}
@Override
@MockData("mockSearch")
public Res search(AddDTO dto) {...}
private Res mockSearch() {
return Res.ok("mock data");
}