mock-server & moco初探
文章目录
000. Readme
- 主要介绍mockserver和moco,前者是重点,后者是辅助理解和比较。
- 但其实比较
github
上的两个项目,无论是在star/fork
还是issue/contributors
上面都不分伯仲,前者稍微占些优势吧。 - 就主要功能而言,两者差不多,但是
mockserver
有更多的使用方式和场景,支持更多的语言和环境。
001. What/Why/When
mock-server/moco
是啥?能干什么?为什么要用?什么时候会用到?
- mock-server/moco都可以模拟任何基于HTTP或HTTPS请求的系统,比如WebService、REST接口等等。
- 当我们需要基于接口开发或测试的时候,我们可以先简单地根据接口约定模拟好各个请求,实现接口开发和使用解耦;当我们需要测试单个接口的时候,希望其它接口正常请求,我们可以只模拟单个接口,做到服务隔离(需要结合
mock-server-proxy
);
010. How
00. moco quick start
- 下载moco jar 包:moco-runner-0.12.0-standalone.jar
- 在jar包同级目录下创建config.json,键入以下内容并保存:
内容是一个json array,array里的每一个对象代表一个HTTP请求的mock,这里没有匹配任何url,表示任何url都会返回相同的结果。[ { "response" : { "text" : "Hello, Moco" } } ]
- 使用命令启动:
java -jar moco-runner-0.12.0-standalone.jar http -p 80 -c config.json
- 访问
http://localhost
就会显示Hello, Moco
- 我们再加一个复杂一点链接规则:
postman访问一下:[ { "response" : { "text" : "Hello, Moco" } }, { "request":{ "uri":"/monitorApplication/alert/confirm", "method":"PUT", "headers":{ "userInfo":"{\"tenantId\":\"3\"}" }, "text":"{\"id\":\"123\"}" }, "response":{ "status":200, "json":{ "code":"1000", "msg":"操作成功!", "data":null } } } ]
- 更多配置:apis.md,基本覆盖了所有http请求的场景,包括重定向、事件等等。
01. moco + maven
首先添加依赖:
<dependency>
<groupId>com.github.dreamhead</groupId>
<artifactId>moco-core</artifactId>
<version>0.12.0</version>
</dependency>
moco + JUnit
public class MocoTest {
@Test
public void should_response_as_expected() throws Exception {
HttpServer server = httpServer(12306);
server.response("foo");
running(server, () -> {
Content content = Request.Get("http://localhost:12306").execute().returnContent();
assertThat(content.asString(), is("foo"));
});
}
}
moco runner
public class MocoRunnerTest {
public static void main(String[] args) {
HttpServer server = httpServer(12306, response(header("Content-Type","application/json;charset=gbk")));
server.put(and(
match(header("userInfo"),".*\"tenantId\":\"3\".*"),
by(uri("/test")),
by(text("{\"id\":\"123\"}"))
)).response(text(new JSONObject().fluentPut("code","100").fluentPut("data","").fluentPut("msg","操作成功!").toJSONString()));
Runner runner = runner(server);
runner.start();
}
}
这样就实现了代码启动,quick start应该也是基于此的一个封装。而且quick start里面的config.json可以实现模块化:
[
{
"context": "/monitorApplication",
"include": "monitorApplication.json"
},
{
"context": "/dbaasDbManage",
"include": "dbaasDbManage.json"
}
]
这样可以实现模块和项目的分离:/dbaasDbManage/*
的链接会按照dbaasDbManage.json
文件的规则匹配,/monitorApplication/*
的链接会按照monitorApplication.json
文件的规则匹配,并且文件会被箭筒,一旦被修改会马上重新加载,不需要重启。
10. mock-server quick start
- 下载all-in-one-jar包:mockserver-netty-5.5.0-jar-with-dependencies.jar
- 命令启动:
java -jar mockserver-netty-5.5.0-jar-with-dependencies.jar -serverPort 8888 -logLevel INFO
- mock server添加mock的方式不是写文件,而是通过REST接口来实现的,具体开放了哪些接口,可以参考文档:mock-server-openapi
- 通过接口添加一个测试expectation:
- 尝试请求:
11. mock server + maven
pom添加依赖
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-netty</artifactId>
<version>5.5.0</version>
</dependency>
mock server
public class MockServerTest {
private static ClientAndServer mockServer;
public static void main(String[] args) {
mockServer = startClientAndServer(10086);
mockServer.when(
request()
.withMethod("PUT")
.withPath("/test")
.withHeader(header("userInfo",".*\"tenantId\":\"3\".*"))
.withBody("{\"id\":\"123\"}")
)
.respond(
response()
.withStatusCode(200)
.withBody(new JSONObject().fluentPut("code","100").fluentPut("data","").fluentPut("msg","操作成功!").toJSONString(), Charset.forName("gbk"))
);
}
}
跟moco是差不多的,但是mock service的写法和功能是比moco多的,mock server能适应更多场景。
这里并不讨论mock server proxy相关的问题。
011. Which
项目 | moco | mock server |
---|---|---|
功能 | 覆盖大部分场景 | 覆盖几乎所有场景 |
学习成本 | 一般 | 一般 |
直接使用server时 配置修改方式 | 修改文件、可持久化、修改不方便无错误验证 | REST接口、不能持久化、修改方便有错误提示 |
二次开发成本(目标是spring+swagger/web+持久化) | 基于netty-http,Json->expectation的逻辑很复杂,可能需要改造后才能复用,难度较高 | 基于Servlet,有现成的Json->expectation的parser,难度一般 |
proxy server | 不支持 | 支持 |
从上面的对比来看,我觉得使用mocker server
是更好地选择。
100. Where
项目 | 跟随项目 | 集中管理 |
---|---|---|
模块化 | 好控制 | 有点难 |
持久化和维护 | 文件,顺便维护接口文档 | 数据库,开发接口时会更新,修改接口时不一定 |
相关度 | 高 | 低 |
开闭原则和维护成本 | 不遵循,维护成本高 | 遵循,维护成本低 |
侵入性 | 高 | 低 |
从上面的对比来看,我觉得集中管理比较合适。