基于Spring Cloud Feign的Mock工具

本地开发需要依赖别人的服务时候,如果不想也把依赖服务启动起来,可以对自己项目中的feign client进行mock,这个工具支持直接在feign client接口上对返回值进行mock,不需要在fallback中编写负责冗长的代码来实现。

如何构建

git clone git@github.com:markytsai/feign-hystrix-mocker.git
mvn clean install -DskipTest=true

如果你知道maven或者gradle的依赖原则,则根据规则引用生成的jar包
如果不清楚,可以直接在spring-cloud-starter-openfeign排除内部引用的feign-hystrix版本,然后自己生成的jar包

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.0.1.RELEASE</version>
    <exclusions>
        <exclusion>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-hystrix</artifactId>
        </exclusion>
    </exclusions>
</dependency>

原理

Feign mocker在feign开源项目feignfeign-hystrix模块功能的基础上,对fallback进行了增强,即对FallbackFactory.Default进行封装,当项目启动构建初始化FallbackFactory时候,会根据feign client是否定义@Mock选择是否使用EnhancedFallbackFactory,以替换FallbackFactory默认的实现FallbackFactory.Default. 如远程调用失败则会进行返回值mock;如果调用成功,则不会进入任何一个FallbackFactory.

使用方法

只需要在远程调用接口上使用@Mock注解,@Mapping注解配置类中字段的值。type是类型,name是在type类型中的字段,值是value。value格式不匹配会抛出异常,这里需要用户保证正确性,代码不做判断。

@Mock(mappings = {
        @Mapping(type = Response.class, name = "code", value = "200")
})
@GetMapping("/getPeople")
Response<People> getPeople();

@Mock(mappings = {
        @Mapping(type = Response.class, name = "code", value = "200"),
        @Mapping(type = People.class, name = "name", value = "mock"),
        @Mapping(type = People.class, name = "age", value = "24"),
        @Mapping(type = Address.class, name = "district", value = "hangzhou"),
        @Mapping(type = Address.class, name = "code", value = "0571"),
})
@GetMapping("/getPeopleEx")
Response<People> getPeopleEx();

使用说明

支持的返回值类型

  1. 范型,比如rpc常用的封装的返回类型 Response, Response的定义如下
@Data
public class Response<T> {

    /**
     * 响应码
     */
    private int code;

    /**
     * 响应描述
     */
    private String msg;

    /**
     * 响应数据
     */
    private T data;
}
  1. 自定义类
@Data
public class People {
    private String name;
    private Integer age;
    private List<Order> orderList;
    public People() {
    }
    public People(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

说明:这里的T不支持java原生类,如Integer, Double等,必须为自定义类

/**
 * T: 不支持 Java包装类型的类,导致返回的data并不是mock的200,而是默认值9
 *
 * @return
 */
@Mock(mappings = {
        @Mapping(type = Response.class, name = "code", value = "200"),
        @Mapping(type = Integer.class, name = "data", value = "200")
})
@GetMapping("/getPeopleEx")
Response<Integer> getInteger();

返回验证

{
    "code": 200,
    "msg": "success",
    "data": [
        {
            "code": 200,
            "msg": "mockString",
            "data": {
                "name": "mock",
                "age": 24,
                "orderList": [
                    {
                        "orderId": 9,
                        "orderName": "mockString",
                        "addressList": [
                            {
                                "district": "hangzhou",
                                "code": "0571"
                            },
                            {
                                "district": "hangzhou",
                                "code": "0571"
                            }
                        ]
                    },
                    {
                        "orderId": 9,
                        "orderName": "mockString",
                        "addressList": [
                            {
                                "district": "hangzhou",
                                "code": "0571"
                            },
                            {
                                "district": "hangzhou",
                                "code": "0571"
                            }
                        ]
                    }
                ]
            }
        },
        {
            "code": 200,
            "msg": "mockString",
            "data": 9
        }
    ]
}{
  "code": 200,
  "msg": "mockString",
  "data": {
    "list": [
      {
        "id": 9,
        "workNo": "mockString"
      }
    ]
  }
}

暂不支持返回值中存在循环依赖。如果有,会抛出异常。

源码仓库:https://github.com/markytsai/feign-hystrix-mocker
详细使用方法参考这个仓库:https://github.com/markytsai/mock-test

原文地址:https://www.cnblogs.com/markytsai/p/15346662.html