Говоря о макете

база данных внешний интерфейс сервер API

Перед чтением

Я надеюсь, что вы можете иметь следующие основы для легкого чтения:

  • ECMAScript 6 (ES6)

Зачем нужен мок

image
Такая сцена, я считаю, каждый будет чувствовать себя дежа вю.

Сегодняшние бизнес-системы редко существуют изолированно.Особенно для крупной компании сотрудничество между различными отделами очень тесное.Нам более или менее необходимо использовать интерфейсные услуги, предоставляемые братскими командами или другими компаниями. В таком случае, это доставит много хлопот нашему совместному тесту на примирение. Если темп каждого братского отдела будет точно таким же, то проблем будет гораздо меньше, но идеал очень полный, реальность очень тощая, добиться одинакового темпа в принципе невозможно.

С этой целью нам нужно использовать некоторые инструменты, которые помогут нам максимально разделить бизнес-единицы, а именно:Mock

Что такое мок

Если mock перевести отдельно, то его значение будет"ложный, ложный", поэтому в области разработки программного обеспечения мы также можем понимать это как«Фейковые данные»,или«Замена реальных данных».

Преимущества насмешек

  • Команды лучше работают параллельно

После использования макета командам не нужно ждать прогресса друг друга, им нужно только согласовать между собой спецификации данных (документы), затем они могут использовать макет для создания удобного интерфейса, а затем разрабатывать и отлаживать Как только самотестирование улучшит ход разработки, оно также значительно продвинет момент времени, когда будут обнаружены дефекты.

  • Включите режим TDD (Test-Driven Development), то есть разработку через тестирование

Модульное тестирование является краеугольным камнем реализации TDD, и TDD часто сталкивается с ситуациями, когда сомодули еще не разработаны, но с моками это не проблема. После определения интерфейса тестер может создать макет, добавить интерфейс в автоматизированную тестовую среду и заранее создать тесты.

  • тестовое покрытие

Например, интерфейс должен возвращать разные значения в различных состояниях. Раньше наш метод состоял в том, чтобы воспроизвести это состояние, а затем запросить интерфейс. Это очень ненаучная практика, и такой способ воспроизведения весьма вероятен. неправильное время или метод работы или даже загрязнение данных в предыдущей базе данных. Если мы используем макеты, нам вообще не нужно беспокоиться об этих проблемах.

  • легкая презентация

Используя Mock для моделирования интерфейса данных, мы можем продемонстрировать продукт без разработки сервера, когда разрабатывается только пользовательский интерфейс.

  • система изоляции

При использовании некоторых интерфейсов, чтобы предотвратить загрязнение базы данных в системе, мы можем настроить эти интерфейсы в режим Mock, чтобы обеспечить чистоту базы данных.

Я полагаю, что после того, как мы выпустили так много моков, всем не терпится попробовать, тогда давайте поговорим о нескольких способах реализации моков.

Реализовать макет

«Упрямая бронза»

Ну начнем с самой упоротой "бронзы" Когда нет мока, как же нам разрабатывать без реального интерфейса?

На моей памяти, когда я сталкиваюсь с этой ситуацией, мой первый подход — записывать данные до смерти в бизнесе, например:

// api
import api from '../api/index';

function getApiMessage() {
    return new Promise((resolve) => {
        resolve({
            message: '请求成功'
        });
    })
    // return api.getApiMessage();
}

Я закомментирую реальный запрос,returnОдинresolveподдельные данныеpromiseВместо реального запроса, когда я вызываю этот метод, он возвращаетresolveМое собственное определение поддельных данныхpromiseа не полученный из интерфейса, который еще не завершенpromise. Выглядит хорошо, по крайней мере, я могу продолжать разработку без интерфейса. Хотя при столкновении со сложными данными списка писать самому немного больно.

Но так ли хорошо, что поддельные данные и бизнес так связаны? Если после завершения реального интерфейса вы забудете удалить эти поддельные данные, потому что бизнес может «работать правильно», так что фактические данные, которые вы используете, всегда были сфабрикованы вами, а не настоящие, то это очень серьезная проблема. . Итак, следующее, о чем нам нужно подумать, это как свести к минимуму запись этих ложных данных в бизнес-код. Чтобы достичь этой цели, давайте официально продвинемся до звания «Золотая слава» макета.

"Золотая слава"

В сегменте макета «Золотая слава» у нас есть очень полезный инструмент:mockJs, Используя mockJs, мы можем генерировать сложные данные интерфейса на основе шаблонов и правил без необходимости писать их самостоятельно, например:

// api
import api from '../api/index';
import Mock from 'mockjs';

function getApiMessage() {
    return new Promise((resolve) => {
        resolve(Mock.mock({
            list|1-20: ['mock数据']
        });
    })
    // return api.getApiMessage();
}
/**
* 通过 Mock.mock 方法和 list|1-20: ['mock数据'] 模板
* 我们将生成一个长度为 1-20, 每个值都为 'mock数据' 数组
*/

Но это всегда делается только для того, чтобы облегчить нам «подделку», и на самом деле мы не можем удалить «подделку» из нашего бизнес-кода. Для достижения этой цели мы можем сначала проанализировать наши потребности:

  • Полное разделение смоделированных данных и бизнес-кода
  • Через некоторую настройку мокается только часть данных, а большая часть данных все равно получается из запроса

Прежде всего, если мы хотим полностью разделить фиктивные данные и бизнес-код, мы должны найти способ делать некоторые статьи при запросе, чтобы он мог получать фиктивные данные вместо запроса реального интерфейса при запросе, что является так называемым «Перехват запроса», а также есть два способа реализации перехвата запроса:

  • Измените запрос, чтобы связать его с фиктивным сервером, и настройте фиктивные данные и маршрутизацию на фиктивном сервере.
// api/index.js
// 通过新增getDataUseMock方法来说明使用了mock方法
import request from '../request';

function getDataUseMock(data) {
    request({
        mock: true
    });
}
// request/index.js
const mockServer = 'http://127.0.0.1:8081';

function request(opt) {
    if (opt.mock) {
        const apiName = opt.api;
        opt.url = `${mockServer}/${apiName}`;
    }
    ...
}
  • При обнаружении использования mock напрямую извлеките данные, соответствующие значению ключа, из файла mock данных.
// api/index.js
// 通过新增getDataUseMock方法来说明使用了mock方法
import request from '../request';

function getDataUseMock(data) {
    request({
        mock: true
    });
}

// request/index.js
import mockData from 'mock/db.js';

function request(opt) {
    if (opt.mock) {
        const apiName = opt.api;
        return new Promise((resolve) => {
            resolve(mockData.apiName)
        })
    }
    ...
}

//mock/db.js
export default {
    '/api/test': {
        msg: '请求成功'
    }
}

На первый взгляд, второй способ кажется более простым, и это правда, но учитывая, что если я буду читать данные прямо из файла, бизнес-поведение также изменится, и запрос будет отправлен не туда, куда он должен быть отправлен. , поэтому я решил создать локальную службу самостоятельно, вернуть разные фиктивные данные, контролируя маршрут, и добавить дополнительные данные к запросу.mockПараметры информируют бизнес о том, какие интерфейсы следует создавать самостоятельноmock-serverПерехват, тем самым сводя к минимуму влияние на первоначальный бизнес.

существуетmock-serverПрежде чем разрабатывать, мы должны понять нашуmock-serverЧто должен уметь:

  • Что вы меняете, так это то, что вы получаете, с возможностью горячего обновления, вам не нужно перезапускать фиктивную службу каждый раз, когда вы добавляете / изменяете фиктивный интерфейс, не говоря уже о перезапуске службы сборки переднего плана.
  • Мок-данные могут быть сгенерированы инструментами без необходимости писать их вручную.
  • Может имитировать запросы POST, GET

Поскольку фиктивные данные хранятся локально, все, что нам нужно, — это сервер без интерфейса, который может отвечать на запросы, поэтому я выбралjson-server

строительствоserverПрежде нам нужно уточнить, какие данные нам нужно моделировать, а какие (mockjs) поддерживать.

// db.js
var Mock = require('mockjs');

// 通过使用mock.js,来避免手写数据
module.exports = {
  getComment: Mock.mock({
    "error": 0,
    "message": "success",
    "result|40": [{
      "author": "@name",
      "comment": "@cparagraph",
      "date": "@datetime"
    }]
  })
};

Во-вторых, нам нужно знать, на какие маршруты доступа мы переходим:

// routes.js
// 根据db.js中的key值,自动生成的路由便是/[key],在route.js中的声明只是为了重定向
module.exports = {
  "/comment/get": "/getComment"
}

Затем мы можем написать наш основной код для запуска сервера:

// server.js
const jsonServer = require('json-server')
const db = require('./db.js')
const routes = require('./routes.js')
const port = 3000;

const server = jsonServer.create()
// 使用mock的数据生成对应的路由
const router = jsonServer.router(db)
const middlewares = jsonServer.defaults()
// 根据路由列表重写路由
const rewriter = jsonServer.rewriter(routes)

server.use(middlewares)
// 将 POST 请求转为 GET,满足可以接受 POST 和 GET 请求的需求
server.use((request, res, next) => {
  request.method = 'GET';
  next();
})

server.use(rewriter) // 注意:rewriter 的设置一定要在 router 设置之前
server.use(router)

server.listen(port, () => {
  console.log('open mock server at localhost:' + port)
})

Следовательно, просто используйтеnode server.jsначатьmock-server, но начинается такserver, а не потому, что я модифицировалroute.jsилиdb.jsИ обновления в реальном времени, то есть мне нужно каждый раз перезагружаться, чтобы обновить свойserver, здесь нам также нужно выполнить небольшую операцию, например, использоватьnodemonследить за нашимиmock-server.

// 将所有和mock相关的文件:db.js route.js server.js 放入mock文件夹
// 然后执行:
$ nodemon --watch mock mock/server.js

// 就能够启动一个能自动热更新的mock-server了。

После этого нам просто нужно использовать код, который мы определили ранее в нашем бизнес-коде, напримерgetDataUseMockметод, вы можете имитировать указанный API.

Хотя мы таким образом завершили полное разделение mock-данных и бизнес-кода, неизбежно использование специального метода в бизнес-коде для объявления того, что мне нужно mock-определить определенный интерфейс, и нам еще предстоит столкнуться, когда mock не требуется. Вопрос в том, чтобы убрать эти методы и заменить их на официально запрошенные методы. Более того, часть данных макета по-прежнему находится в той же директории git, что и бизнес-код, и только разработчик имеет право изменять и добавлять его, что не совсем соответствует той роли, которую должен выполнять макет.

С этой целью я проконсультировался с руководителями отдела и «генеральными» разработчиками, чтобы определить, какой макет нам нужен:

  • Его можно использовать, изменив код в бизнесе как можно меньше.mock
  • Модифицированный бизнес-код не повлияет на обычный бизнес-процесс
  • mock-serverДолжен быть для всех, а не только для фронтенд-разработчиков
  • Возможность визуализации изменений и дополненийmockинтерфейс иmockданные
  • Возможность поддержки нескольких проектов одновременно

С помощью этих основных принципов наш макет, наконец, продвинулся до ранга «Вечный бриллиант».

«Вечный бриллиант»

С благословением бриллиантового ранга я нашелmock-server«прицельное оружие»: отБиблиотека инструментов THX с открытым исходным кодом для команды разработчиков AliRAP2 в , который содержит в себе преимущества именно то, что мне нужно для макета. в соответствии сонлайн учебник,будетRAP2После развертывания на нашем локальном сервере нам нужно только настроить его локальноhostsфайл для доступа к нашему собственномуRAP2, после этого все, что нам нужно сделать, это обработка в бизнес-коде:

  • Его можно использовать, изменив код в бизнесе как можно меньше.mock
  • Модифицированный бизнес-код не повлияет на обычный бизнес-процесс

Для того, чтобы модифицировать код как можно меньше и чтобы измененный код не влиял на нормальный бизнес-процесс, нам необходимо добавить специальный режим разработки, только в этом режиме разработки измененный код вступит в силу, либо будет только существовать.

Режим разработки, который мы добавили к нам, можно назвать фиктивным режимом разработки, Чтобы отличить этот режим разработки, мы используем переменные среды в nodejs для различения.

"scripts": {
    "dev:mock": "cross-env MOCK=true npm run dev"
}

в настоящее время используетcross-envПосле объявления переменной среды мы можем передатьprocess.env.MOCKПолучите значение объявленной нами переменной окружения, когда мы увеличимMOCKпеременная существует иtrueТолько когда мы выполняем фиктивный перехват запросов.

Но недостаточно просто объявить это, нам также нужно сообщить бизнес-коду, какие интерфейсы нужно мокировать. Поэтому нам также нужен список, который существует только в фиктивном режиме, чтобы сообщить нам, какие интерфейсы должны быть фиктивными.

// config.js
if (process.env.MOCK) {
    config.mockList = [
        '/api/test',
        '/api/needMock'
    ]
} else {
    config.mockList = [];
}

Конечно, вы также можете использовать условную компиляцию, чтобы определить, следует лиconfig.mockListВ вашем коде это лучший вариант.

Затем вам нужно только сравнить mockList конфигурации с API, который вы в настоящее время запрашиваете в своем инкапсулированном методе запроса, чтобы определить, нужно ли его имитировать.

import config from '../config/config';

const mockServer = 'http://rap2.xxx.com'

function request(opt) {
    const apiName = opt.api;
    if (config.mockList && config.mockList.includes(apiName)) {
        opt.url = `${mockServer}/${apiName}`;
    }
    ...
}

Таким образом, наш макет, наконец, достиг своей окончательной формы.С этого момента, пока документ интерфейса (даже интерфейс макета RAP2 может быть непосредственно использован в качестве документа интерфейса), мы можем разрабатывать и тестировать его по желанию~

Использование RAP2

Начните с команды

Команда является высшей единицей склада.Команда может иметь несколько фиктивных складов, но не только команда может владеть складами, но и отдельные лица. Цель использования команды состоит в том, чтобы защитить репозитории, входящие в команду, от посторонних, а также сохранить команду закрытой (конечно, вы также можете сделать команду общедоступной).

склад

Склад — это высшая единица интерфейса, которая может принадлежать отдельному лицу или группе. Каждый склад может назначать разработчиков, а назначенный персонал может изменять или добавлять интерфейс склада. Неназначенный персонал может только просматривать интерфейс. Склад имеет определенный префикс доменного имени репозитория. Правила доменного имени интерфейса при этом следующие:${仓库前缀域名}${接口配置域名}, и каждое хранилище предоставляет интерфейс для получения текущих данных хранилища.

интерфейс

Давайте сначала посмотрим на состав страницы конфигурации интерфейса:

image
Вы можете видеть, что страница интерфейса в основном состоит из следующих частей:

  • Новый интерфейс (список интерфейсов)
  • интерфейсный модуль
  • Детали интерфейса (параметры запроса и параметры ответа)

В сведениях об интерфейсе маршрут запрошенного фиктивного интерфейса создается при создании интерфейса, а интерфейс автоматически генерируется после создания, а адрес запроса${仓库域名}${接口路由}.

Для частичной настройки параметров запроса мы в основном ориентируемся на правила генерации и значения по умолчанию, на чьи правила и шаблоны можно ссылаться.mockJsизДокументацияСпецификация синтаксиса в , правила генерации следуют数据模板定义规范(Data Template Definition,DTD), следует значение по умолчанию数据占位符定义规范(Data Placeholder Definition,DPD).

Содержание цитаты