自定义注解返回mock数据
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; } }
使用:在实现类方法上使用,指定mock方法
@Override @MockData("mockSearch") public Res search(AddDTO dto) {...} private Res mockSearch() { return Res.ok("mock data"); }
其中 Res 是返回封装类,没有其他特殊作用。mockModal 是配置是否使用mock数据的配置项。