Что такое Мок
Mock, как следует из названия, представляет собой симуляцию. Обычно тот же интерфейс используется для имитации объекта вместо реального объекта, что позволяет эффективно изолировать внешние зависимости и облегчить тестирование. Для фронтенд-разработки Mock, как важная часть, может принести множество преимуществ:
- Front-end и back-end параллельная разработка
- Имитирует различные значения отклика для легкого тестирования
- Он может заранее обнаруживать некоторые проблемы с макетом страницы при экстремальных значениях отклика и т. д.
задний план
Фронтенд-разработку можно условно разделить на три этапа: этап параллельной разработки, этап совместной отладки и этап тестирования. Большинство текущих фронтенд-проектов отделены от фронтенда и бэкенда, и неизбежно столкновение с проблемой источников данных на этапах разработки и совместной отладки.
На этапе совместной отладки в каждой среде есть реальные данные, что удобно для локальной отладки, обычно мы указываем интерфейс на реальный источник данных. Если существуют междоменные ограничения, вы можете использовать отладочные прокси-инструменты, такие как Charles и Fiddler, чтобы решить эту проблему, или вы можете запустить локальный сервер:
const express = require('express');
const proxy = require('http-proxy-middleware');
const app = express();
app.use('/api', proxy({ target: 'your-api-url', changeOrigin: true }));
app.listen(3000);
Если он все еще находится в стадии параллельной разработки, то нам нужны Mock-данные.В целом, есть следующие распространенные методы:
1. Перехватывать запросы Ajax и Fetch
Недостатки: Грязный код, смешанный во внешнем интерфейсе, не может эффективно имитировать сетевые условия.
2. Локальный фиктивный сервер
Недостатки: Интерфейсов много, а стоимость создания и модификации высока.
3. Платформа управления интерфейсом YApi и Easy Mock
Недостаток: недостаточно гибкий. Например, по каждому интерфейсу разбросана некоторая информация о конфигурации, которой нельзя управлять централизованно, а стоимость модификации высока.
В этой статье Swagger, с которым автор много раз сталкивался, используется в качестве примера для исправления недостатков локального Mock Server, которому необходимо постоянно создавать интерфейсы с одной стороны. Откройте сеть адреса пользовательского интерфейса Swagger, предоставленного серверной частью, и найдите файл API-docs.
Этот файл JSON содержит такую информацию, как интерфейс, метод запроса и формат ответа. Можно представить, что парсить этот файл не сложно, единственное хлопотное дело может быть парсинг и преобразование типа значения ответа. Если вы сможете своевременно синхронизировать данные с локальным фиктивным сервером, вы сможете сэкономить много утомительной физической работы.
Talk is cheap
1. Цели
- Путь к интерфейсу соответствует каталогу Mock, который легко найти и изменить.
- С методом запроса в качестве имени файла один метод соответствует одному файлу, что снижает конфликты при редактировании несколькими людьми.
- Используйте Mock.js для переноса значений ответов, чтобы легко имитировать некоторые экстремальные ситуации.
2. Разберите файл JSON
Ранее мы упоминали, что сложность парсинга файлов JSON в основном заключается в преобразовании типов значений ответа, здесь для этого мы используем модуль парсинга Easy Mock.
const swaggerParserMock = require('swagger-parser-mock');
const synchronizeSwagger = {
init({ url, blacklist, outputPath }) {
this.url = url;
this.blacklist = blacklist;
this.outputPath = outputPath;
this.parse();
},
async parse() {
const { paths } = await swaggerParserMock(this.url);
this.generate(paths);
console.log(paths);
}
}
synchronizeSwagger.init({
// Swagger api-docs地址
"url": "your-api-docs-url",
// 输出目录
"outputPath": "./routes",
// 黑名单,跳过一些不需要同步的api
"blacklist": []
});
Информация о путях печати, формат примерно следующий:
"/path/foo": {
"get": {
"summary": "bar",
"responses": {
"200": {
"example": "'@string'" // 模块为我们做的类型转化和Mock.js包装。
}
}
},
"post": {
"summary": "baz",
"responses": {
"200": {
"example": "'@string'"
}
}
}
}
3. Пройдитесь по интерфейсу. Мы можем добавить черный список, чтобы отфильтровать некоторые интерфейсы, которые бесполезны для внешнего интерфейса. Уменьшите количество сбоев и улучшите ремонтопригодность.
const fs = require('fs');
const { join } = require('path');
const { promisify } = require('util');
const mkdirp = require('mkdirp');
const writeFile = promisify(fs.writeFile);
const mkdir = promisify(mkdirp);
const synchronizeSwagger = {
// 遍历api path信息
traverse(paths) {
for (let path in paths) {
if (this.blacklist.includes(path)) {
continue;
}
for (let method in paths[path]) {
const pathInfo = paths[path][method];
if (!pathInfo['responses']['200']) {
continue;
}
this.generate(path, method, pathInfo);
}
}
}
}
4. Создайте Mock-файл, в который можно добавить комментарии и другую информацию.
const synchronizeSwagger = {
// 生成mock文件
async generate(path, method, pathInfo) {
const outputPath = join(__dirname, this.outputPath, path);
const {
summary,
responses: { 200: responseOK },
} = pathInfo;
try {
// 生成目录
await mkdir(outputPath);
const example = responseOK['example'];
// 生成文件内容
const template = this.generateTemplate({
summary,
example,
method,
path,
});
// 生成文件, 已存在的跳过,避免覆盖本地以及编辑的文件
const fPath = join(outputPath, `${method}.js`);
await writeFile(fPath, template, { flag: 'wx' });
console.log(`增加Mock文件:${fPath}`);
} catch (error) {
/* eslint-disable no-empty */
}
},
generateTemplate({ summary, example, method, path }) {
// prettier-ignore
// api path中的{petId}形式改为:petId
return `/**
${summary}
**/
const Mock = require("mockjs");
module.exports = function (app) {
app.${method}('/api${path.replace(/\{([^}]*)\}/g, ":$1")}', (req, res) => {
res.json(Mock.mock(${example}));
});
};`;
},
}
5. Запустите фиктивный сервер
Взяв в качестве примера экспресс, мы используем динамическую функцию require для создания маршрута, который сопоставляется с только что созданным файлом интерфейса.
const fs = require('fs');
const join = require('path').join;
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.listen(port, function() {
console.log(`server is listening ${port}`);
});
function scan(path, app) {
const files = fs.readdirSync(path);
for (let i = 0; i < files.length; i++) {
const fpath = join(path, files[i]);
const stats = fs.statSync(fpath);
if (stats.isDirectory()) {
scan(fpath, app);
}
if (stats.isFile()) {
require(fpath)(app);
}
}
}
scan(join(__dirname, './routes'), app);
напиши в конце
До сих пор мы использовали пользовательский интерфейс Swagger для синхронизации данных Mock.Если мы добавим промежуточное программное обеспечение, такое как cors и body-parser, в основном формируется локальный сервер Mock. Для облегчения синхронизации мы добавляем его в скрипты npm.
"scripts": {
"ss": "node ./synchronizeSwagger.js"
},
Выполните npm run ss, чтобы сгенерировать соответствующие фиктивные данные и интерфейс доступа.
Приложение:образец кода