mb详解
上面主要介绍了mb的环境安装及其关键术语,和一个简单的demo,那么接下来我们逐步了解。
其他语言客户端支持
如果你对nodejs不熟或者很倔不想接收新的语言,可以在下面找到自己的熟悉的语言,如果没有要自己去写了。
说实在的,对于有上心的开发者是难不倒的,一点就通!
语言 | 工程 | 作者 |
---|---|---|
C# | MbDotNet | Matthew Herman |
Clojure | Charlatan | Matthew Daley |
Go | GoBank | Erkan |
Java | javabank | James Thomas |
JavaScript | mountebank-helper | Alex |
Perl | Test::Mountebank | Dagfinn Reiersøl |
PHP | Juggler | Andrejs Mironovs |
Python | mountepy | Michał Bultrowicz |
Ruby | mountebank-gem | Michael Cheng |
Shell | mountebank-sh | Sergi Bech Robleda |
TypeScript | node-mountebank | Ron van der Wijngaard |
启动脚本
看到这里应该明白了mb究竟是个什么东东,但怎么开发、启动一个自己的服务估计还有些迷糊,那么我们从启动说起。
mb start --configfile imposters.ejs --allowInjection &
上面我说了常用的参数,这个启动指令里包含 start、--configfile、--allowInjection。
start顾名思义就是启动mb
--configfile 后面跟的imposters.ejs就是模板文件,EJS是一个JavaScript模板库,用来从JSON数据中生成HTML字符串。
有时通过配置文件加载imposters更方便,而不是通过API(就是通过指令,我也嫌麻烦就没提)加载它们。
我们可以在EJS文件里面定义端口、通讯协议、存根等,对于多个服务的模块化开发相当便利。
--allowInjection 是否允许脚本注入,后面详解。
EJS文件脚本
本次讲解主要是http的挡板服务,由于时间有限,smtp、tcp请参照官方文档或等后续文档。
imposters.ejs文件的内容是json格式的数据,具体如下:
{
"imposters": [
<% include ./test/test1.json %>,
<% include ./test/test2.json %>,
<% include ./test/test3.json %>
]
}
ejs内容比较简单,就是imposters的配置,它是json数组,通过include加载多个json文件来注入到imposters配置中,如test1.json是支付的挡板代码,
test2.json是实名认证的挡板代码,这样从架构的角度,各司其职、分而治之不同的业务挡板不同的配置文件,便于并行开发和维护。
JSON文件脚本
test1.json文件json的格式如下,可以根据注释了解其整个结构。
{
"port": 1234,<!-- 指定端口 -->
"protocol": "http",<!-- 指定协议 -->
"stubs": [{<!-- 可以多个元素 -->
"predicates": [{
"equals": {<!-- 如果请求url 为/test/demo时触发本stub-->
"path": "/test/demo",<!-- 访问路径 -->
"method": "post"<!-- 提交方法 -->
}
}, {}],<!-- 可以多个元素 -->
"responses": [{
"is": {
"statusCode": 200,
"headers": {
},
"body": {
}
},
"_behaviors": {
"shellTransform": ["node ./test/test.js"]<!-- 脚本注入 -->
}
}, {}]<!-- 可以多个元素 -->
},
{<!-- 请求不匹配时响应内容,如果没有谓词匹配,则发送默认响应 -->
"responses": [{
"is": {
"statusCode": 400,<!-- 服务器不理解请求的语法,这里可以随意定义的哈 -->
"headers": {
},
"body": {
}
}
}]
}]
}
<font color="red">注意
最后一个应答是没有predicate匹配,则发送默认响应,就是我们写代码是swich时的default。
</font>
说起http协议,一定要说下状态码,有时候面试官也会经常问起,目前大多数服务化治理都是采用http通讯协议。
下面简单的提下,便于大家理解,技术这玩意也是个关系网,简单的服务也会涉及到很多领域。
做前端的兄弟们一定要记住,因为大多是中后台兄弟的问题,这个时候可以吊他们一次。
1开头系列:表示请求已接收,继续处理
100
2开头系列:成功--表示请求已被成功接收、理解、接受
200 ok 表示请求成功返回网页
3开头系列:表示重定向,要完成请求必须进行更进一步的操作
301 永久跳转
302 临时跳转,请求的网页已临时跳转到新位置。
4开头系列:客户端错误--请求有语法错误或请求无法实现
400 服务器不理解请求的语法。
401 请求要求身份验证。对于登录后请求的网页,服务器可能返回此响应。
403 表示用户得到授权(与401错误相对),但是访问是被禁止的,服务器收到请求但是拒绝提供服务
404 网页没有发现
406 用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
5开头系列:服务器端错误--服务器未能实现合法的请求
500 内部服务器错误
502 一般是网关服务器请求后端服务时,后端服务没有按照http协议正确返回结果。
503 服务当前不可用, 可能因为超载或停机维护。
504 一般是网关服务器请求后端服务时,后端服务没有在特定的时间内完成服务。
protocol常用设置
协议这块http默认就可以了,https的话最好配置下私钥和证书,这样核心系统调用时不会出现警告。
{
"port": 1234,
"protocol": "https",
"key": "",<!-- SSL服务器私钥 -->
"cert": "",<!-- SSL服务器证书 -->
...
}
predicates常用配置
predicate决定存根是否匹配,不管怎样它返回就是一个boolean值,true或false,如果返回true就返回对应的response响应,只要这个清楚,那么下面的所有花哨都很一般。
常用运算符
运算符 | 描述 |
---|---|
equals | 请求字段与谓词匹配 |
deepEquals | 在请求的数据包含某个关键字及对应的值(例如query,http中的字段) |
contains | 请求字段包含谓词 |
startsWith | 请求字段以谓词开头 |
endsWith | 请求字段以谓词结束 |
matches | 请求字段与正则表达式匹配。 |
exists | 是否存在 |
not | 取反 |
or | 满足其中一个条件 |
and | 同时满足条件 |
inject | 注入JavaScript以确定请求是否匹配 |
常用的条件设置
equals
{
"port": 8081,
"protocol": "http",
"stubs": [{
"predicates": [{
"equals": {
"path": "/test",
"method": "get"
}
}],
"responses": [{
"is": {
"body": {
"Operator": "equals"
}
}
}]
}]
}
浏览器访问后结果http://localhost:8081/test
{
"Operator": "equals"
}
deepEquals
{
"port": 8081,
"protocol": "http",
"stubs": [{
"predicates": [{
"deepEquals": {
"query": {
"key": ["first", "second"]
}
}
}],
"responses": [{
"is": {
"body": {
"Operator": "deepEquals"
}
}
}]
}]
}
浏览器访问后结果http://localhost:8081/test?key=second&key=first
{
"Operator": "deepEquals"
}
exists
{
"port": 8081,
"protocol": "http",
"stubs": [{
"predicates": [{
"exists": {
"method": true,
"body": false
}
}],
"responses": [{
"is": {
"body": {
"Operator": "exists"
}
}
}]
}]
}
浏览器访问后结果http://localhost:8081/test
{
"Operator": "exists"
}
还有其他场景判断
"exists": {
"method": true,<!-- get或post -->
"body": false <!-- 没有body,就是get情况-->
}
"exists": { "body": true }<!-- post情况 -->
inject 脚本注入设置
{
"port": 8081,
"protocol": "http",
"stubs": [{
"predicates": [{
"inject": "function (config) {return config.request.body.indexOf('inject') === 0; }"
}
],
"responses": [{
"is": {
"body": {
"Operator": "inject"
}
}
}]
}]
}
通过postman post方法提交,http://localhost:8081/test,提交数据包含inject,返回结果如下:
{
"Operator": "inject"
}
<font color="red">注意
inject的函数在这里不能进行编排,造成编写、调试代码不方便,可以采用下面导入文件的方式解决,包括responses注入也适应。
</font>
inject利用stringify导入模板脚本
{
"port": 8081,
"protocol": "http",
"stubs": [{
"predicates": [{
"inject": "<%- stringify(filename, './test/inject.ejs') %>"
}],
"responses": [{
"is": {
"body": {
"Operator": "inject"
}
}
}]
}]
}
inject.ejs脚本
function(config) {
return config.request.body.indexOf('mounte') === 0;
}
<font color="red">注意
其他的操作都是对tcp数据的操作,在这里不做过多解释,有需要可以和我沟通或去官网去查帮助。
</font>
xpath脚本
是挡板接收xml数据的时候进行条件的判断,由于我们的服务大多是基于restful的,所以这种场景使用不多,全凭烧下大脑,越来越聪明。
{
"port": 8081,
"protocol": "http",
"stubs": [{
"predicates": [{
"equals": {
"body": "Harry Potter"
},
"xpath": {
"selector": "//title"
},
"caseSensitive": true,
"comment": "case sensitivity applies to the selector as well as the value"
}],
"responses": [{
"is": {
"body": {
"Operator": "xpath"
}
}
}]
}]
}
通过postman post方法提交,http://localhost:8081/,提交数据如下:
<books xmlns:isbn="http://schemas.isbn.org/ns/1999/basic.dtd">
<book>
<title>Harry Potter</title>
<isbn:summary>Dragons</isbn:summary>
</book>
</books>
返回的结果如下:
{
"Operator": "xpath"
}
caseSensitive区分大小写,true或false。
selector查找xml那个节点,本示例是查的title节点。
系统测试利器之挡板实战(一)
系统测试利器之挡板实战(二)
系统测试利器之挡板实战(四)
系统测试利器之挡板实战(五)
系统测试利器之挡板实战(六)
系统测试利器之挡板实战终结(七)