什么是stubby4j?

Stubby4J是基于Java编写的,该项目是由个人发起的开源项目,它是一款非常灵活可配置的基于HTTP(s)协议测试Web服务交互的工具,采用内嵌式的Jetty作为HTTP服务器,它的主要作用在于,可以在集成测试时,用来模拟第三方Web服务的API行为,比如,目前比较流行的RESTful架构风格的Web服务。

为什么使用Stubby4J?

  • 模拟HTTP请求,Stub第三方API的返回数据
  • 在写集成测试时,Mock第三方API更加便捷
  • 能够验证发送的所有参数并指定详细返回数据
  • 目前支持所有HTTP方法:GET, POST, PUT, PATCH, DELETE, HEAD等
  • 支持HTTP和HTTPS协议,同时可模拟返回的错误码
  • 在性能测试和稳定性测试时,支持定义延时返回
  • 使用相对简单,配置非常便捷,启动也很快速

如何使用Stubby4J?

命令行快速启动

首先需要下载JAR包,假设本地已经安装了Java,然后在本地创建一个名为cfg.yml的文件:

cfg.yml
1
2
3
4
5
6
7
8
- request:
method: GET
url: /hello-world
response:
status: 200
headers:
Content-Type: application/json
body: Hello World!

运行如下命令启动Stubby4J:

1
2
3
4
5
6
7
8
$ java -jar stubby4j-3.3.0.jar -d cfg.yml
Loaded: [GET] /hello-world
Admin portal configured at http://localhost:8889
Admin portal status enabled at http://localhost:8889/status
Stubs portal configured at http://localhost:8882
Stubs portal configured with TLS at https://localhost:7443 using internal keystore
Jetty successfully started

然后访问http://localhost:8882/hello-world可以看到返回的Hello World!字样。

如果需要进入Admin Portal,可以访问http://localhost:8889/status查看Stub的数据。

更多命令行使用方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
usage:
java -jar stubby4j-x.x.xx.jar [-a <arg>] [-d <arg>] [-da] [-ds]
[-h] [-k <arg>] [-l <arg>] [-m] [-o] [-p <arg>] [-s <arg>] [-t
<arg>] [-v] [-w]
-a,--admin <arg> Port for admin portal. Defaults to 8889.
-d,--data <arg> Data file to pre-load endpoints. Valid YAML
1.1 expected.
-da,--disable_admin_portal Does not start Admin portal
-ds,--disable_ssl Does not enable SSL connections
-h,--help This help text.
-k,--keystore <arg> Keystore file for custom TLS. By default TLS
is enabled using internal keystore.
-l,--location <arg> Hostname at which to bind stubby.
-m,--mute Mute console output.
-o,--debug Dumps raw HTTP request to the console (if
console is not muted!).
-p,--password <arg> Password for the provided keystore file.
-s,--stubs <arg> Port for stub portal. Defaults to 8882.
-t,--tls <arg> Port for TLS connection. Defaults to 7443.
-v,--version Prints out to console stubby version.
-w,--watch Periodically scans for changes in last
modification date of the main YAML and
referenced external files (if any). The flag
can accept an optional arg value which is
the watch scan time in milliseconds. If
milliseconds is not provided, the watch
scans every 100ms. If last modification date
changed since the last scan period, the stub
configuration is reloaded

集成测试中的具体应用

首先在Gradle中配置依赖,在build.gradle中加入其依赖,只会在集成测试时使用,所以只需要加入testCompile即可:

1
testCompile 'by.stub:stubby4j:3.3.0'

然后需要在加载应用程序Context前启动Stubby4J,常用启动stubby4j的方法如下:

1
2
3
4
5
startJetty("stubby4j.yml") # localhost默认端口: Stubs(8882), Admin(8889) and SslStubs portals(7443)
startJetty(8882, "stubby4j.yml") # 可以指定Stubs端口,其它为默认值
startJetty(8882, 8889, "stubby4j.yml") # 可以指定Stubs和Admin端口,其它为默认值

在集成测试启动之前执行startJetty,需要在其Base父类中加入以下代码:

1
2
3
4
5
6
private static final StubbyClient API_STUB = new StubbyClient();
@BeforeClass
public static void startUp() throws Exception {
API_STUB.startJetty(8882, new ClassPathResource("api/stubby4j.yml").getFile().getAbsolutePath());
}

其中api/stubby4j.yml文件位于集成测试代码的resources目录下。

在集成测试运行完成后需要停止stubby4j服务stopJetty

1
2
3
4
@AfterClass
public static void shutDown() throws Exception {
API_STUB.stopJetty();
}

具体示例可参阅GitHub Demo: service-stubmock stubby4j

基于YAML文件的示例

示例一:模拟GET请求并返回Json格式Payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- request:
method: GET
url: ^/users/111$
response:
status: 200
headers:
content-type: application/json
body: >
{"userId": 111, "userName": "Peter"}
- request:
method: GET
url: /users/123
response:
status: 404

其中的request:url支持正则表达式,比如^/[a-z]{3}-[a-z]{3}/[0-9]{2}/[A-Z]{2}/[a-z0-9]+$

示例二:在request时指定多个methods

1
2
3
4
5
6
7
8
9
- request:
url: /anything
method: [GET, HEAD]
- request:
url: /anything
method:
- GET
- HEAD

示例三:可以指定查询参数

1
2
3
4
5
6
- request:
url: ^/with/parameters$
method: GET
query:
search: search terms
filter: month

其中query中的元素会匹配url后的查询参数?key1=value1&key2=value2,并且任意顺序都可以被匹配到,以下两组URL都会被匹配到:

  • /with/parameters?search=search+terms&filter=month
  • /with/parameters?filter=month&search=search+terms

如果查询参数只有KEY没有VALUE,则匹配时URL需要给定KEY,Payload如下:

1
2
3
4
5
6
- request:
url: ^/with/parameters$
method: GET
query:
search:
filter: month

则以下两组URL都会被匹配到:

  • /with/parameters?search&filter=month
  • /with/parameters?search=&filter=month

示例四:POST时指定发送的Payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- request:
url: ^/path/to/something$
method: POST
headers:
Content-Type: application/json
authorization-basic: "bob:password"
x-custom-header: "^this/is/\d/test"
post: >
{"key": value, "data": "content"}
response:
headers:
Content-Type: application/json
status: 201
body: Your request was successfully processed!

示例五:返回的Response是Json文件

1
2
3
4
5
6
7
8
- request:
method: GET
url: /users/456
response:
status: 200
headers:
Content-Type: application/json
file: json/users-response.json

其中的file路径是当前YAML文件的相对路径。

Request和Response的Payload除了使用JSON外,还可以使用XML格式或直接使用文本,另外配置文件除了使用YAML格式外,也可以合适JSON格式。更多示例可以参考github stubby4j


References