通常,在开发移动应用程序时(Web应用程序可能存在相同的问题),开发人员会发现自己处于后端无法正常工作或无法提供必要方法的情况。
由于各种原因,可能会发生这种情况。 但是,通常在开发开始时,后端根本没有编写,而客户端没有它就开始了。 在这种情况下,开发的开始会延迟2-4个月
有时服务器只是关闭(崩溃),有时没有时间推出必要的方法,有时会出现数据问题等。 所有这些问题导致我们编写了一个小型的Mocker服务,该服务可让您替换实际的后端。

我怎么来的我怎么来的? 我在公司的第一年即将结束,他们把我带入了一个全新的电子商务项目。 经理说,该项目需要在4个月内完成,但是后端团队(在客户方)将仅在1.5个月后开始开发。 在这段时间里,我们必须抛出很多UI功能。
我建议编写一个Moch后端(在成为iOS开发人员之前,我曾在Uni中使用.NET玩过)。 实现想法很简单:根据给定的规范,有必要编写存根方法,该方法将从预先准备好的JSON文件中获取数据。 他们决定了这一点。
2周后,我去度假,心想:“为什么我不自动生成所有这些?” 因此,在放假2周的过程中,我编写了一个类似的解释器,该解释器采用APIBlueprint规范并从中生成.NET Web App(C#代码)。
结果,这个东西的第一个版本出现了,我们使用了将近2.5个月。 我无法提供实际数字,这对我们有多大帮助,但我记得他们回想起来,如果不是该系统,它将不会发布。
现在,几年后,我考虑了我所犯的错误(其中有很多),并完全重写了该仪器。
借此机会-非常感谢提供反馈和建议的同事。 对于那些忍受了我所有的“工程任意性”的领导人也是如此。
引言
通常,任何客户端-服务器应用程序都类似于以下内容:

每个屏幕至少有1个查询(并且经常有更多查询)。 深入屏幕,我们需要发出越来越多的请求。 有时,直到服务器告诉我们“显示按钮”,我们才能进行过渡。 也就是说,移动应用程序不仅在其直接工作期间而且在开发阶段都与服务器紧密相关。 考虑抽象产品开发周期:

- 首先我们设计。 我们分解,描述和讨论。
- 收到任务和要求后,我们开始开发。 我们编写代码,排版等。
- 在我们实现了某些东西之后,正在准备一个程序集,该程序集将进行手动测试,在该程序中检查应用程序的不同情况。
- 如果我们一切正常,并且测试人员对组件进行了测试,则由执行验收的客户承担。
这些过程中的每一个都很重要。 尤其是后者,因为客户必须了解我们真正处于哪个阶段,有时他需要向管理层或投资者报告结果。 通常,此类报告会以移动应用程序演示的格式出现。 在我的实践中,有一种情况是客户仅展示了MVP的一半,而MVP仅适用于Mokas。 mok应用看起来像礼物,嘎嘎像礼物。 所以这是真实的(:
但是,这是一个粉红色的梦。 让我们看看如果没有服务器,实际会发生什么。

- 由于我们无法正常编写服务,也无法检查所有情况,因此开发过程将更加缓慢且痛苦,我们必须编写存根,稍后需要将其删除。
- 在悲伤地完成了一半组装之后,测试人员便看到了它,却不知道该怎么做。 您什么也无法检查,有一半根本无法工作,因为没有服务器。 结果,他们错过了许多错误:逻辑和视觉错误。
- 好吧,在“他们看起来如何”之后,您需要将组装交给客户,然后最不愉快的事情就开始了。 客户无法真正评估作品,他从所有可能的案例中发现1-2个案例,当然也无法向投资者展示该作品。
总的来说,一切都在下坡。 不幸的是,这种情况几乎总是发生:有时几个月没有服务器,有时半年没有,有时只是在此过程中服务器很晚,或者您需要快速检查可以使用真实服务器上的数据操作来重现的边界情况。
例如,如果用户的付款时间超过到期日,我们想检查应用程序的行为。 在服务器上重现这种情况非常困难(而且很长),我们需要人为地做到这一点。
因此,存在以下问题:
- 服务器完全丢失。 因此,不可能进行设计,测试和展示。
- 服务器没有时间,这会干扰开发并可能会干扰测试。
- 我们要测试边界情况,并且服务器不能在没有长手势的情况下允许这种情况。
- 影响测试并威胁演讲。
- 服务器崩溃(在稳定的开发过程中,我们丢失了服务器3.5天)。
为了解决这些问题,创建了Mocker。
工作原理
Mocker是一个小型Web服务,位于某个地方,可侦听特定端口上的流量,并且可以使用预先准备好的数据来响应特定的网络请求。
顺序如下:
1.客户端发送请求。
2. Mocker收到请求。
3. Mocker找到所需的模拟。
4. Mocker返回所需的模拟。
如果在点1,2和4都清楚了,那么3会提出问题。
为了了解服务如何找到客户端必需的模拟,我们首先考虑模拟本身的结构。
Mock是以下格式的JSON文件:
{ "url": "string", "method": "string", "statusCode": "number", "response": "object", "request": "object" }
让我们分别分析每个字段。
网址
此参数用于指定客户端访问的请求的URL。
例如,如果移动应用程序向url
host.dom/path/to/endpoint
发出请求,那么在
url
字段中,我们需要
/path/to/endpoint
写入
/path/to/endpoint
。
也就是说,此字段存储
到端点的
相对路径 。
该字段的格式应为url模板格式,即允许以下格式:
/path/to/endpoint
-正常的网址。 收到请求后,服务将逐字符比较行。/path/to/endpoint/{number}
-带有路径模式的url。 具有此类URL的模拟文件将响应与该模式匹配的任何请求。/path/to/endpoint/data?param={value}
-带有参数模式的url。 具有此类url的模拟将触发包含给定参数的请求。 此外,如果参数之一不在请求中,则它将与模板不匹配。
因此,通过控制URL参数,您可以清楚地确定某个模拟将返回到特定的URL。
方法
这是预期的http方法。 例如
POST
或
GET
。
该字符串只能包含大写字母。
statusCode
这是响应的http状态代码。 也就是说,通过请求此模拟,客户端将收到状态记录在statusCode字段中的响应。
回应
此字段包含JSON对象,该对象将在对其请求的响应主体中发送给客户端。
要求
这是预期从客户端接收到的请求的主体,将用于根据请求的请求主体给出所需的响应。 例如,如果我们想根据请求参数更改答案。
{ "url": "/auth", "method": "POST", "statusCode": 200, "response": { "token": "cbshbg52rebfzdghj123dsfsfasd" }, "request": { "login": "Tester", "password": "Valid" } }
{ "url": "/auth", "method": "POST", "statusCode": 400, "response": { "message": "Bad credentials" }, "request": { "login": "Tester", "password": "Invalid" } }
如果客户端通过正文发送请求:
{ "login": "Tester", "password": "Valid" }
然后他会收到以下响应:
{ "token": "cbshbg52rebfzdghj123dsfsfasd" }
并且如果我们想检查如果密码输入错误的话应用程序将如何工作,那么将随正文一起发送一个请求:
{ "login": "Tester", "password": "Invalid" }
然后他会收到以下响应:
{ "message": "Bad credentials" }
而且我们可以使用错误的密码检查情况。 其他所有情况也是如此。
现在,我们将弄清楚如何分组和搜索所需的最小起订量。

为了快速轻松地搜索所需的Mok,服务器将所有Moka加载到内存中并以正确的方式对其进行分组。 上图显示了分组示例。
服务器通过
url和
method组合了不同的Moka。 除其他事项外,这是必需的,以便我们可以在一个URL上创建许多不同的Mok。
例如,我们希望不断拉动“推入刷新”,出现不同的答案,并且屏幕状态一直在变化(以检查所有边界情况)。
然后,我们可以使用相同的
方法和
url参数创建许多不同的mok,然后服务器将迭代地将它们返回给我们。
例如,让我们有这样的摩卡:
{ "url": "/products", "method": "GET", "statusCode": 200, "response": { "name": "product", "currency": 1, "value": 20 } }
{ "url": "/products", "method": "GET", "statusCode": 200, "response": { "name": "gdshfjshhkfhsdgfhshdjgfhjkshdjkfsfgbjsfgskdf", "currency": 5, "value": 100000000000 } }
{ "url": "/products", "method": "GET", "statusCode": 200, "response": null }
{ "url": "/products", "method": "GET", "statusCode": 400, "response": null }
然后,当我们第一次调用GET / products方法时,我们将首先得到答案:
{ "name": "product", "currency": 1, "value": 20 }
当我们第二次调用时,迭代器指针将移至下一个元素并返回给我们:
{ "name": "gdshfjshhkfhsdgfhshdjgfhjkshdjkfsfgbjsfgskdf", "currency": 5, "value": 100000000000 }
如果我们获得了一些大价值,我们可以检查应用程序的行为。 依此类推。
好了,当我们到达最后一个元素并再次调用该方法时,第一个元素将再次返回给我们,因为迭代器将返回到第一个元素。
缓存代理
Mocker可以在缓存代理模式下工作。 这意味着,当服务收到来自客户端的请求时,它将取出真实服务器所在的主机的地址以及方案(用于确定协议)。 然后,它将接收到的请求(包含所有标头,因此,如果该方法需要身份验证,则可以,您的
Authorization: Bearer ...
传输),并从请求中剪切服务信息(相同的
host
和
scheme
),并将请求发送到真实服务器。
收到第200个代码的响应后,Mocker将答案保存到Mock文件中(是的,然后您可以复制或更改它),然后将其从真实服务器收到的内容返回给客户端。 而且,它不仅将文件保存到一个随机的位置,还可以组织文件以便您可以手动使用它们,例如,Mocker向以下URL发送请求:
hostname.dom/main/products/loans/info
。 然后,它将创建一个
hostname.dom
文件夹,然后在其中创建一个
main
文件夹,在其中创建一个
products
文件夹...
为了避免重复的模拟,该名称是基于
http方法 (GET,PUT ...)和
来自真实服务器的响应主体的哈希值形成的 。 在这种情况下,如果某个特定答案已经存在模拟,那么它将被简单地覆盖。
可以针对每个请求单独激活此功能。 为此,向请求添加三个标头:
X-Mocker-Redirect-Is-On: "true", X-Mocker-Redirect-Host: "hostaname.ex:1234", X-Mocker-Redirect-Scheme: "http"
明确指示模拟的路径
有时,您希望Mocker仅返回我们想要的那些Moka,而不返回项目中的所有Moka。
与测试人员特别相关。 对于他们来说,为每个测试用例准备一套准备好的Moka会很方便。 然后,在测试过程中,QA只需选择所需的文件夹即可安静地工作,因为不再有来自第三方模拟的噪音。
现在这是可能的。 为了启用此功能,您需要使用特殊的标头:
X-Mocker-Specific-Path: path
例如,让Mocker在根目录具有这样的文件夹结构
root/ block_card_test_case/ mocks.... main_test_case/ blocked_test_case/ mocks...
如果您需要运行有关被屏蔽卡的测试案例,那么
X-Mocker-Specific-Path: block_card_test_case
如果您需要运行与锁定主屏幕相关的测试用例,则
X-Mocker-Specific-Path: main_test_case/blocked_test_case
介面
最初,我们直接通过ssh与mokas进行合作,但是随着mokas和用户数量的增加,我们切换到了更方便的选项。 现在,我们正在使用CloudCommander。
在docker-compose示例中,它绑定到Mocker容器。
看起来像这样:

好吧,奖金是一个网络编辑器,它使您可以直接从浏览器添加/更改moki。

这也是一个临时解决方案。 在计划中,摆脱了通过文件系统访问Moks到某些数据库的问题。 相应地,将有可能从GUI到此DB控制Moka本身。
部署方式
部署Mocker的最简单方法是使用Docker。 此外,从docker部署服务将自动部署基于Web的界面,通过该界面可以更轻松地使用mokas。 通过Docker部署所需的文件位于存储库中。
但是,如果此选项不适合您,则可以从源代码中独立组装服务。 足够了:
git clone https://github.com/LastSprint/mocker.git cd mocker go build .
然后,您需要编写一个配置文件(
example )并启动该服务:
mocker config.json
已知问题
- 在每个新文件之后,您需要执行
curl mockerhost.dom/update_models
以便该服务再次读取文件。 我没有找到一种快速而优雅的方式来更新它 - 有时CloudCommander会出错(或者我做错了什么),并且它不允许编辑通过Web界面创建的moki。 通过清除浏览器缓存来处理它。
- 该服务仅适用于
application/json
。 该计划支持form-url-encoding
。
总结
Mocker是一项Web服务,解决了由于某种原因服务器未准备就绪时开发客户端服务器应用程序的问题。
该服务允许您为单个URL创建许多不同的模拟,允许您通过在URL中显式指定参数或直接通过设置期望的请求主体来将请求和响应相互连接。 该服务具有基于Web的界面,可大大简化用户的生活。
服务的每个用户都可以独立添加必要的端点和他需要的请求。 在这种情况下,在客户端上,为了切换到真实服务器,只需将常量替换为主机地址就足够了。
我希望本文能对遇到类似问题的人们有所帮助,也许我们会共同努力开发此工具。
GitHub存储库