SpringBootTest测试框架一

为了方便开发,对数据进行mock处理,形成文件,只修改文件内容达到mock指定数据的目的

1、定义测试模式

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface TestModel {

    TestModelEnum value() default TestModelEnum.LOCAL_PRIOR;

    String[] mockMethodNames() default {};
}

public enum TestModelEnum {

    /**
     * 读取本地数据,若无则抛异常
     */
    LOCAL,
    REMOTE,
    /**
     * 本地优先,若本地无mock数据则调用远端并保存到本地
     */
    LOCAL_PRIOR,
}


注入拦截器

public class TestBean {

    public static final String mockMethods = "mockMethods";

	// feign拦截器,为了mock feign返回值
    @Bean
    public Feign.Builder feignBuilder() {
        return Feign.builder().invocationHandlerFactory((target, dispatch) -> new FeignResultInvocationHandler(target, dispatch));
    }


	// sql拦截器,为了mock 查询sql返回值
    @Bean
    public SqlResultInterceptor sqlResultInterceptor() {
        return new SqlResultInterceptor();
    }
}

启动测试父类

StartApplication 为springboot的启动类,可自定义测试启动类也可直接复用项目启动类

@SpringBootTest(classes = {StartApplication.class, TestBean.class})
public abstract class AbstractBasicTest {
    public final Logger logger = LoggerFactory.getLogger(getClass());


	// 方法启动时初始化执行方法,可指定db等
    @Before
    public void before() {
        logger.info("before ==================================init datasource====");
    }

	// 方法结束时执行方法,清除变量
    @After
    public void tearDown() {
        // 清理环境变量,恢复测试环境
        System.clearProperty("classPath");
        System.clearProperty("classMethodName");
        System.clearProperty("className");
        System.clearProperty("testModel");
        System.clearProperty(TestBean.mockMethods);
    }

	// 每个测试方法执行前初始化方法,赋值变量值
    @BeforeEach
    public void initService(TestInfo testInfo) throws Exception {
        Method method = testInfo.getTestMethod().get();
        String methodName = method.getName();
        String className = testInfo.getTestClass().get().getName();

        logger.info("initService before each ============> current className:{},methodName:{}", className, methodName);

        String classPath = TestFileHelper.getClassPath(className);
        System.setProperty("classPath", classPath);
        System.setProperty("className", className);
        System.setProperty("classMethodName", methodName);

        TestModel annotation = method.getAnnotation(TestModel.class);
        if (annotation != null) {
            TestModelEnum value = Optional.ofNullable(annotation.value()).orElse(TestModelEnum.LOCAL_PRIOR);
            System.setProperty("testModel", value.name());

            String[] mockInterfaces = Optional.ofNullable(annotation.mockMethodNames()).orElse(new String[0]);
            System.setProperty(TestBean.mockMethods, String.join(",", mockInterfaces));
        }

    }

     
    protected String compareAndWrite(Object obj, boolean isCover){
        Pair<String, String> pair = getFile(obj);


        String filePath = pair.getKey();
        String content = pair.getRight();

        boolean exist = TestFileHelper.isExist(filePath);
        String oldResult = "";
        if (exist) {
            oldResult = TestFileHelper.readFile(filePath);
        }

        boolean isEqual = content.equals(oldResult);
        logger.info("=====> compare result isEqual : {} : \n oldResult:{} \n newResult:{} \n ", isEqual, oldResult, content);

        if (isCover) {
            TestFileHelper.writeFileObj(obj, filePath);
        }

        Assertions.assertEquals(content, oldResult, "result is not equal");

        return content;
    }


    protected Pair<String, String> getFile(Object obj) {
        String content = TestFileHelper.toJSONString(obj);

        String path = System.getProperty("classPath");
        String methodName = System.getProperty("classMethodName");
        String fileName = "result.json";
        String filePath = Paths.get(path, methodName, fileName).toString();

        return Pair.of(filePath, content);
    }



}

工具类

public class TestFileHelper {
    public static final Logger logger = LoggerFactory.getLogger(TestFileHelper.class);

    private static Map<String, Integer> sameMethodCountMap = Maps.newConcurrentMap();

    private static String getNumSuffix(String methodName){
        String className = System.getProperty("className");
        String classMethodName = System.getProperty("classMethodName");
        // 测试类名 + 测试方法名 + 执行类名_执行方法名
        String key = className + classMethodName + methodName;
        Integer integer = 0;
        try {
            integer = sameMethodCountMap.getOrDefault(key, 0);
            if (integer == 0) {
                return "";
            }
        } finally {
            sameMethodCountMap.put(key, integer + 1);
        }
        return integer == 0 ? "" : String.valueOf(integer);
    }

    protected static String getFilePath(String methodName) {
        String suffix = getNumSuffix(methodName);

        String path = System.getProperty("classPath");
        String classMethodName = System.getProperty("classMethodName");
        String fileName = methodName.substring(methodName.lastIndexOf(".") + 1) + suffix + ".json";

        return Paths.get(path, classMethodName, fileName).toString();
    }

    public static Object getResult(String methodName, Function mockFunction, Function remoteFunction) throws Throwable{
        boolean isMock = false;
        String testModel = System.getProperty("testModel");
        String filePath = getFilePath(methodName);

        Object result = null;
        try {
            if (TestModelEnum.LOCAL.name().equals(testModel)) {
                boolean exist = TestFileHelper.isExist(filePath);
                if (!exist) {
                    throw new RuntimeException(String.format("mock 文件不存在,文件名=【%s】", methodName));
                }
                isMock = true;
                result = mockFunction.apply(filePath);
            } else if (TestModelEnum.REMOTE.name().equals(testModel)) {
                String mockInterfaces = System.getProperty(TestBean.mockMethods);
                if (StringUtils.isNotBlank(mockInterfaces) && mockInterfaces.toLowerCase().contains(methodName.toLowerCase()) && TestFileHelper.isExist(filePath)) {
                    isMock = true;
                    result = mockFunction.apply(filePath);
                } else {
                    result = remoteFunction.apply(filePath);
                }
            } else {
                boolean exist = TestFileHelper.isExist(filePath);
                if (exist) {
                    isMock = true;
                    result = mockFunction.apply(filePath);
                } else {
                    result = remoteFunction.apply(filePath);
                    TestFileHelper.writeFileObj(result, filePath);
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            logger.info(String.format("%s [%s] %s result is : %s",
                    isMock ? "MOCK" : "REMOTE",
                    testModel, methodName, JSONObject.toJSONString(result)));
        }
        return result;
    }

    public static String getClassPath(String className) {
        String classPath = getTargetResourcePath();
        String pathPrefix = classPath.substring(0, classPath.indexOf("/target"));
        String substring = className.substring(0, className.lastIndexOf("."));
        String packageName = substring.replaceAll("\\.", "/");

        Path path = Paths.get(pathPrefix, "/src/test/java", packageName);

        return path.toString();

    }

    public static String getTargetResourcePath(){
        String classPath = ClassLoader.getSystemResource("").getPath();
        if (classPath.startsWith("/")) {
            classPath = classPath.substring(1);
        }
        return classPath;
    }

    public static boolean isExist(String fileName){
        File file = new File(fileName);
        return file.exists();
    }

    public static String readFile(String fileName) {
        try {
            String content = FileUtils.readFileToString(new File(fileName));
            return content;
        } catch (Exception e) {
            logger.error("readFile error", e);
        }

        return null;
    }

    public static boolean writeFileObj(Object obj, String fileName) {
        try {
            String content = toJSONString(obj);
            Path path = Paths.get(fileName);
            if (!Files.exists(path.getParent())) {
                Files.createDirectories(path.getParent());
            }

            FileUtils.writeStringToFile(new File(fileName), content, "UTF-8");

            return true;
        } catch (Exception e) {
            logger.error("writeFile error", e);
        }

        return false;
    }

    public static String toJSONString(Object obj){
        return JSONObject.toJSONString(obj,
                SerializerFeature.PrettyFormat,
//                    SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);
    }





}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值