江湖郎中,你要吗?
不知道说到江湖郎中,大家会想到什么。很多人可能就要联想到自己一些悲催的伤心往事,之前有同事就曾经被江湖郎中欺骗,买了很多茶叶,往事不堪回首。
今天我其实想和大家聊的话题是mountebank,为什么mountebank会和江湖郎中联系在一起呢? 因为mountebank直译的话就是“江湖郎中,骗子”, mountebank官方的图中给出的图片也很有意思,也是一个人拿着一瓶药,一副“我有药,你要吗” 的形象,如下图:
image什么是江湖郎中?
Mountebank其实就是提供假的API的一个工具,其实光看字面意思也很好理解。他是第一个开源的能够提供跨平台,支持的多协议的一个工具,而且使用起来也很简单,只要把你的端口指向mountebank就可以了。 Mountebank通过配置一个或者多个imposters文件,唯一需要注意的是各个imposter的监控端口不可重复,否则会有一个imposter不会被加载。
为什么要搭建自己的mock server?
可能很多人就要问,现在不都已经开始流行契约测试了吗? 契约即为mock,那为什么还要专门的mock services呢。其实最主要原因是第三方系统的集成,比如和银行系统集成,和SAP系统集成。这个时候其实并不需要用到契约测试,契约测试一般用于微服务架构,或者前后端分离开发等。而Mock一般是仅仅为了模拟第三方系统,是更加轻量级的架构。
在我们当前的项目中就同时用到了契约测试(pact)和MockServer(Mountebank)。整体项目架构是WEB->BFF->Platform(微服务)->SAP(客户的第三方系统)。契约测试主要是运用于前端分离开发(BFF和platform之间),以及platform的微服务之间,而Mountebank主要是用来模拟SAP系统。
在项目初期,考虑到了以下几个方面,我们决定在项目初期使用mock server:
1. 客户的SAP测试系统是一个第三方的系统,在项目初期表现的不太稳定,导致开发过程中不能很好的和SAP集成,影响开发进度。
2. 关于测试数据,由于在测试和UAT的环境里面提供的测试数据有限,在测试中我们希望能够覆盖更多的测试场景,来测试某些边界值。
3. 其次,是关于持续集成,其中包括与SAP的集成测试,试想如果SAP不稳定,怎样去做持续集成;即使是SAP变的稳定了,还有另外一个棘手的问题就是,我们当前只有读的权限,如何在SAP里面创建我们所需要的测试数据,以得到我们期望的测试结果?
综合这些原因所以我们决定搭建自己的mock server。
为何我们选择了Mountebank
其实还有很多工具都和Mountebank又类似的功能,比如很常见的moco,也能够提供类似的服务,为何选择了mountebank呢?
1. 由于安全方面的原因,客户的环境不能访问外网,很多依赖不能下载安装的限制,Mountebank提供了binary的安装包,只需要把binary的包考到相应的环境里,不需要任何安装的步骤,非常方便。
2. Mountebank的predicates功能,提供了多种断言类型对请求进行断言,比如equals, deepEquals, contains等,如下表,个人认为比moco等更加灵活。
Operator | Description |
---|---|
equals | The request field matches the predicate |
deepEquals | Performs nested set equality on the request field, useful when the request field is an object (e.g. the query field in http) |
contains | The request field contains the predicate |
startsWith | The request field starts with the predicate |
endsWith | The request field ends with the predicate |
matches | The request field matches the JavaScript regular expression defined with the predicate |
exists | If true, the request field must exist. If false, the request field must not exist |
not | Inverts a predicate |
or | Logically or's two predicates together |
and | Logically and's two predicates together |
inject | Injects JavaScript to decide whether the request matches or not. See the injection page for more details |
3. 还有一些其他的原因,比如mountebank提供了录制,回放等功能。
Mountebank的具体用法
Imposters
一个Imposter会占⽤用⼀个端⼝,并且提供个提供⼀系列接口的应⽤。如下图,stubs就是模拟服务,一个Imposter可以包含多个stubs,每个stub可以由⼀对responses和predicates组成,Mountebank会通过⾃自上⽽而下的方式对stubs进⾏匹配
{
"imposters": [
{
"port": 4547,
"protocol": "http",
"stubs": [
<% include MockResponseForApiOne.json %>,
<% include MockResponseForApiTwo.json %>,
<% include SAPmockOdataSet.json %>,
<% include SAPmockOdataSet1.json %>,
<% include SAPmockRest.json %>,
<% include SAPmockRestGetOneUser.json %>
]
}
]
}
Predicates
Mountebank提供了很丰富的predicates,上面已经提到,比如equals,deepEquals,contains,startsWith,endWith,可以很方便在Json文件里面进行定义,下面例子的predicates,就定义了必须是“get方法”,路径必须为“/sap/opu/odata/sap/ZHELLO_SRV/DeveloperSet”,而且query必须是"sap-language":"EN",才能获得相应的response。如果想知道某一种predicates的具体用法,详见 http://www.mbtest.org/docs/api/predicates
"predicates": [
{
"equals": {
"method": "GET"
}
},
{
"equals": {
"path": "/sap/opu/odata/sap/ZHELLO_SRV/DeveloperSet",
"query": { "sap-language": "EN" }
}
}
]
Response
当满足了predicates之后,才能得到相应的response,就像下面的情况,当body里面有email和password,并且是Post的方法,且满足path为/Apitesting/v1/test?type=ResponseTwo,才能得到200的response,并且返回相应的body。
{
"responses": [
{
"is": {
"statusCode": 200,
"body": {
"Text": "Response ONE ",
"token": "username",
"expires_in": 90
}
}
}
],
"predicates": [
{
"exists": {
"body": {
"username": true,
"password": true
},
"method": "POST",
"path": "/Apitesting/v1/test?type=ResponseOne"
}
}
]
}
一般来说,同⼀个stub可以包含多个response,当满⾜断言时,Mountebank会自上而下的返回response,当然Response还支持其他类型,比如proxy,inject等。
Response Type | Description |
---|---|
is | Merges the specified response fields with the response defaults (see the protocol page linked to from the sidebar on the left for the defaults) |
proxy | Proxies the request to the specified destination and returns the response. The response is saved and can be replayed on subsequent calls |
inject | Allows you to inject a JavaScript function to create the response object |
关于一些其他的用法,官方文档已经将的很详细了,大家可以详见http://www.mbtest.org/。
需要注意的几点
上面其实提到了很多关于mock server的优点,比如可以在SAP系统不稳定的时候方面的支持开发,可以用来创建更多类型的测试数据等等。但是需要再项目中想清楚下面几点:
- 什么时候做集成测试? 集成测试越早越好,并不是我们有mock server后就万事大吉了,我们仍然需要更早的进行集成测试。
- 及时关注契约的变化,mock server和契约测试不一样,契约测试可以理解为双方的,而mock server更多的是单方的,所以在项目过程要随时关注mock的真实的系统的契约变化。
- 在测试的过程中,虽然能够方便的创建很多边界场景,但是数据不够多元化,还是需要结合真正的第三方系统进行测试。
希望再提到江湖郎中时,大家不仅仅想到的是某些伤心过往,”江湖郎中“在某些情况下还真的能够药到病除。