如何根據protobuf來Mock後臺返回的數據

Protobuf

Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內部的混合語言數據標準,他們用於 RPC 系統和持續數據存儲系統。前端

Protocol Buffers 是一種輕便高效的結構化數據存儲格式,能夠用於結構化數據串行化,或者說序列化。它很適合作數據存儲或 RPC 數據交換格式。可用於通信協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。爲何要講到它,由於咱們後臺的協議就是用的它。git

Mock

Mock也能夠叫mock object,模擬對象,在面向對象程序設計中,以可控的方式模擬真實對象行爲的假對象。前端比較有名的庫是Mock.jsgithub

爲何要mock呢?
一、先後端分離,並行開發,可以充分利用人力,避免等待。
二、能夠豐富測試用例,提早模擬不少的真實場景數據,而沒必要等到線上環境才發現問題。ajax

但Mock.js有個問題:學習和配置成本高。npm

// 配置 Mock 路徑
require.config({
    paths: {
        mock: 'http://mockjs.com/dist/mock'
    }
})
// 加載 Mock
require(['mock'], function(Mock){
    // 使用 Mock
    var data = Mock.mock({
        'list|1-10': [{
            'id|+1': 1
        }]
    })
    // 輸出結果
    document.body.innerHTML +=
        '<pre>' +
        JSON.stringify(data, null, 4) +
        '</pre>'
})


// ==>
{
    "list": [
        {
            "id": 1
        },
        {
            "id": 2
        },
        {
            "id": 3
        }
    ]
}

用它以前必需要先配置一個Ajax的請求路徑,而後根據後臺的協議,學習mock的語法,才能模擬出list這個數組。因此這裏存在着兩個問題:
一、配置成本和語法學習成本
二、後臺協議轉換爲mock語法json

不少時候,等到咱們開發完業務邏輯,已經沒有多少耐心來寫這個mock邏輯,簡單的協議還好,若是涉及到很複雜的,寫這個mock的邏輯就更加不肯意。gulp

爲了幫前端同窗偷個懶,有必要把這個過程給省了。後端

Protobuf轉換爲JSON

git上已經有針對Protobuf開源的js接口:https://github.com/dcodeIO/pr...。由於構建工具咱們使用的是gulp,一樣的也有個對應的插件:gulp-protobufjs,可是無法拿來就用。數組

首頁咱們來看下這個gulp-protobufjs插件所作的事情安全

var gulp = require('gulp');
var gulpprotobuf = require('gulp-protobufjs');
 
gulp.task('default', function () {
  return gulp.src('file.proto')
    .pipe(gulpprotobuf())
    .pipe(gulp.dest('out/'));
});

讀取proto文件,而後生成一個文件,文件類型能夠自定義。
若是產出的是.js文件,那麼結果是commonjs模塊文件:

module.exports = require("protobufjs").newBuilder({})['import']({
    "package": "mmgameweappwap",
    "syntax": "proto2",
    "messages": [
        {
            "name": "User",
            "syntax": "proto2",
            "fields": [
                {
……

若是是.json文件:

{
    "package": "mmgameweappwap",
    "syntax": "proto2",
    "messages": [
        {
            "name": "UserItem",
            "syntax": "proto2",
            "fields": [
                {
                    "rule": "required",
                    "type": "string",
                    "name": "user_id",
                    "id": 1
                },
                {
                    "rule": "optional",
                    "type": "string",
                    "name": "head_img_url",
                    "id": 2
                },
                {
                    "rule": "optional",
                    "type": "string",
                    "name": "nick_name",
                    "id": 3
                }
            ]
        },
……

很顯然,這不是咱們想要的最終結果。咱們想要的結果是最終的ajax返回的數據。固然有了協議的json結構,字段類型、字段名也都有了,剩下的事情就只需根據他們mock一些數據。這個json文件能夠理解爲對接口的一個描述文件。

pb協議的rule常見的有如下幾種:

  • optional:可選

  • required:必須

  • repeated:數組

數據類型,有如下幾種最基本的類型,基本均可以映射爲js經常使用的數據類型。

圖片描述

例子

在解析pb文件的時候,後臺CGI接口名會被定義爲message。

package mmgameweappwap;
message GetDiceGameRoomRequest {
    required string room_id = 1;
}
message GetDiceGameRoomResponse {
    required int32 errcode = 1;
    required string errmsg = 2;

    optional OkResult data = 3;
    message OkResult {
        repeated UserDiceItem user_dice_list     = 1;
        required uint32 room_close_remain_second = 2;
        required bool room_closed                = 3;
    }
}

package 能夠理解爲模塊,上文咱們定義了一個mmgameweappwap模塊。

  • GetDiceGameRoomRequest:請求的message

  • GetDiceGameRoomResponse:返回的message

  • GetDiceGameRoom:接口名稱

一個CGI接口在pb協議中的定義通常會成對的出現。RequestResponse是全部接口標準的後綴,以區別普通的message。依賴這種規則,就能夠把接口解析出來,而且也可以知道其請求、返回的message。

從上面的pb協議看,message能夠被嵌套,OkResult是屬於GetDiceGameRoomResponse子message。同一個pb文件下,message名可能重複,整個協議能夠當作是一顆樹。若是要找對應的message,必須從當前節點的子節點開始查找,不然可能找錯。

處理的流程比較簡單。以下圖所示:

圖片描述

經過分析知道接口名後,若是前端的請求都是統一的,就能夠經過請求接口的代碼模板生成請求代碼。生成對應的API.js:

var Promise = require('js/libs/Promise');
var Util    = require('js/common/util');
var Mock = require('./mock');
var app     = getApp();

var FETCH_URL   = 'http://xxxxx/gameweappwap/';
module.exports = {
   getDiceGameRoom: function(data) {
        return new Promise((resolve, reject) => {
            if(app.mock){
                resolve(Mock.getDiceGameRoom);
                return;
            }
            app.request({
                url: FETCH_URL + 'getsmobapremadeinfo',
                data: {
                    room_id: data.room_id, // string 
                },
                method: "POST",
                header: {
                    'content-type': 'application/json'
                },
                success: resolve,
                fail: reject,
……

exports對外的接口就是CGI的接口名:getDiceGameRoom。
request中的roomid就是從pb協議中解析出來的,後面的註釋標註了其類型。這樣一個ajax請求就很是的簡單明瞭了。開發者只須要API.getDiceGameRoom調用便可。若是當前app.mock開發開啓,就回直接返回mock數據。mock數據是與API.js同級的文件。
圖片描述

這裏的數據都是調用mock.js生成的,固然咱們能夠加入一些業務的數據,這樣測試起來更加真實。

運用場景

一、前端安全,模擬xss例子。
圖片描述

隨機生成一些xss用例,用於前端頁面的測試。

二、前端UI測試。

在實際工做中,常常會遇到文本截斷的問題。UI界面在多行文本的狀況下會不會表現正常這個問題,在這種狀況下就能夠輕易的測試出來,而不需每次叫後臺開發配合加一些假數據。

以下圖,咱們能夠針對字符串類型的數據生成一些長文本。
圖片描述

結語

全部的項目都在統一框架下,每一個項目都保持統一的目錄結構,只須要自定義一些配置就能初始化項目腳手架,剩下的只須要專一於業務開發。
圖片描述

by addy 原創文章,歡迎轉載,但但願全文轉載,註明本文地址。http://www.iamaddy.net/2017/0...

相關文章
相關標籤/搜索