MSW:可用于浏览器和测试的Mock服务

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 在 VUE 项目开发中,大部分需求会涉及API数据交互,为了保证项目效率,前端通常需要一个 API 服务器来确保前端开发进度,这就是所谓的 Mock 服务。网络上有许多类型的 Mock 工具,使用不同的方法解决同一个问题。

在 VUE 项目开发中,大部分需求会涉及API数据交互,为了保证项目效率,前端通常需要一个 API 服务器来确保前端开发进度,这就是所谓的 Mock 服务。网络上有许多类型的 Mock 工具,使用不同的方法解决同一个问题。

主要包括两种类型:

  • 一种是使用服务器语言(如Node.js、PHP)模拟一个服务器
  • 另一种是使用拦截器拦截请求然后重定向到前端准备好的处理函数。

拦截器方式的 Mock 工具,在 VUE 中常用的有 axios-mock-adapter ,但是它对于 API 类型的支持不够,如 REST 或者 GraphQL API

本文带大家来认识一下 Mock Service Worke(MSW),一个功能完善的 API Mock 工具,它可以使用 Service Worker 拦截HTTP请求,可以模拟真实的 HTTP 请求,可以使用浏览器的 DevTools 进行查看,并且是在 Service Worker 级别上工作。MSW 也可以用在项目的测试代码中,不必为项目的 HTTP 响应设置额外的测试。文章涉及的代码在 GitHub 及REST Api相关知识可以参阅专栏《布道API》。

什么是MSW

Mock Service Worker 是一个 API 模拟库,它使用 Service Worker API 来拦截实际请求。 —— MSW docs

注意:Service Worker 只能在浏览器环境中工作。在 Node.js 环境中,MSW 利用 Node.js 的请求拦截器库,并允许重用来自浏览器环境的相同模拟定义。

什么是Service Worker

MSW 依赖于 Service WorkerService Worker 本质上是浏览器在后台运行的脚本,它是完全独立于它正在处理或服务的网页。它们充当了 web 应用程序、浏览器和网络之间的代理服务器,目的是为前端应用程序创建一个良好的离线体验,关于 Service Worker 的更多内容可以参阅《ServiceWorker工作原理、生命周期和使用场景》。而 MSW 就是建立在 Service Worker 的缓存机制之上的。

为了更好的介绍 MSW 的使用,下面从创建一个全新的应用开始。

创建VUE应用

使用 Vue CLI 创建一个新的 Vue 应用程序,在终端中,执行下面的命令:

vue create vue-msw

选择第三个选项:

image.png

回车后,选择 Unit Testing ,按下空格键,然后回车:

image.png

选择 3.x (Preview)

image.png

然后选择默认选项:

image.png

然后选择单元测试项,选择 Jest:

image.png

接下来步骤继续默认选项,最后出现下面的内容,输入 N

image.png

创建项目完成后,由于需要用到 AJAX 通讯,下面将安装最熟悉的依赖 axios ,如下:

yarn add axios // 或者 npm install axios --save

打开项目文件,创建路径和文件 /src/services/axios.js ,代码如下:

import axios from "axios";
const apiClient = axios.create({
    baseURL: "/api",
});
apiClient.interceptors.response.use(
    (response) => {
        return response.data;
    },
    (error) => {
        return Promise.reject(error || error.response);
    }
);
export const getArticle = async (articleId) => {
    const response = await apiClient.get(`/articles/${articleId}`);
    return response;
};

接下打开项目文件 src/App.vue ,将默认代码替换为以下代码:

<template>
    <blockquote v-if="error">{{ error }}</blockquote>
    <div v-if="detail">
        <h4>
            <a :href="detail.url" target="_blank">{{ detail.title }}</a>
        </h4>
        <p>{{ detail.content }}</p>
    </div>
</template>
<script>
import { getArticle } from "@/services/axios";
export default {
    data() {
        return {
            articleId: 3,
            detail: null,
            error: null,
        };
    },
    async created() {
        try {
            this.detail = await getArticle(this.articleId);
        } catch (error) {
            this.error = "API服务异常";
        }
    },
};
</script>

现在可以启动项目了,运行代码:

yarn serve // npm run serve

打开浏览器,输入地址,将看到异常信息:API服务异常。打开开发者工具,可以看到接口返回 404 状态,这是因为接口不存在导致的。

创建Mock

先增加依赖 msw ,执行命令:

yarn add msw  // npm install msw --save

安装完成后,在目录 src 中创建文件夹 mocks,并创建两个文件,分别为 handlers.jsbrowser.js ,分别的用途如下:

  • handlers.js  :主要为定义API逻辑的代码
  • browser.js :使用 handlers.js  中的代码初始化模拟的 service worker

/src/mocks/handlers.js 代码如下:

import { rest } from "msw";
const articles = [
    {
        id: 1,
        title: "Node.js 日志最佳实践指南",
        content:
            "在开发阶段,无论是日志记录还是调试,都可以很容易地跟踪程序并检测到错误。但是在生产环境中,应该考虑更多关于日志记录的问题,因为这对于应用程序的监视和故障排除非常关键。",
        url: "https://juejin.cn/post/7017811851345920037",
    },
    {
        id: 2,
        title: "NodeJs 全栈创建多文件断点续传",
        content:
            "文件上传,算是项目开发中比较常见的需求,本文将展示如何构建一个多文件断点续传组件,可以同时处理多个文件,并可以在出现异常或者网络中断的情况下恢复上传,可以手动暂停和恢复文件的上传。文章内容涉及前端和后端,算是一个小型的全栈项目,项目将使用 NodeJs、Express、Busboy 和 XMLHttpRequest,并使用自己开发的脚手架 generator-norm 来构建项目。",
        url: "https://juejin.cn/post/7015935144007729189",
    },
    {
        id: 3,
        title: "Node.js 日志之winston使用指南",
        content:
            "Winston 是强大、灵活的 Node.js 开源日志库之一,理论上, Winston 是一个可以记录所有信息的记录器。这是一个高度直观的工具,易于定制。",
        url: "https://juejin.cn/post/7018169629176496158",
    },
];
export const handlers = [
    rest.get(`/api/articles/:id`, (req, res, ctx) => {
        const { id } = req.params;
        const data = articles.find((item) => item.id === parseInt(id, 10));
        if (data) {
            return res(ctx.status(200), ctx.json(data));
        } else {
            return res(ctx.status(500));
        }
    }),
];
export const defaultHandlers = [];

/src/mocks/browser.js 代码如下:

import { setupWorker } from "msw";
import { handlers, defaultHandlers } from "./handlers";
export const mocker = setupWorker(...handlers, ...defaultHandlers);

至此,Mock 的逻辑基本完成,接下来需要将其引入到项目中,修改文件 src/main.js ,加入下面代码:

if (process.env.NODE_ENV === "development") {
    const { mocker } = require("./mocks/browser");
    mocker.start({
        // 对于没有 mock 的接口直接通过,避免异常
        onUnhandledRequest: "bypass",
    });
}

接下来将在 public 文件夹中生成一个 Service Worker 脚本:

npx msw init public/

执行完成之后,会创建一个 js 文件,不过不用去做任何修改,再次启动项目,效果如下:

image.png

打开开发者工具,查看网络请求,如下:

image.png

而  axios-mock-adapter  实现的 Mock 再开发工具中无法查看到。

MSW 用于测试

MSW 的美妙之处在于,可以重用相同的处理代码进行测试。

测试将使用Vue测试库(VTL),因为它的设计理念和 MSW 更贴合。测试将模拟客户端请求。接下来修改 package.json 增加 3 个开发依赖库:

"devDependencies": {
    "@testing-library/vue": "^6.3.4",
    "@testing-library/jest-dom": "^5.11.9",

保存后,执行一下代码:

yarn install  // npm install

完成后,创建目录 tests/unit , 并创建文件 App.spec.js ,代码如下:

import App from "@/App";
import { setupServer } from "msw/node";
import { rest } from "msw";
import { render, screen, waitFor } from "@testing-library/vue";
import "@testing-library/jest-dom";
import { handlers } from "@/mocks/handlers";
import * as axios from "@/services/axios";
const server = setupServer(...handlers);
const getArticleSpy = jest.spyOn(axios, "getArticle");
beforeAll(() => {
    server.listen();
});
afterEach(() => {
    getArticleSpy.mockClear();
    server.resetHandlers();
});
afterAll(() => {
    server.close();
});
describe("App", () => {
    it("调用API:getArticle 获取文章 id 为 3 的文章信息", async () => {
        server.use(
            rest.get("/api/articles/3", (req, res, ctx) => {
                return res(ctx.status(200));
            })
        );
        render(App);
        expect(getArticleSpy).toHaveBeenCalledTimes(1);
    });
    it("显示一个服务器异常错误", async () => {
        server.use(
            rest.get("/api/articles", (req, res, ctx) => {
                return res(ctx.status(500));
            })
        );
        render(App);
        expect(getArticleSpy).toHaveBeenCalledTimes(1);
    });
});

上面测试代码只对API请求的状态码进行测试,运行下命令:

sudo npm run test:unit

image.png

总结

正如上面介绍的,MSW 不仅可以用于构建 Mock 服务,还能用于测试。


相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
10月前
|
Dubbo 应用服务中间件 API
使用 Apifox、Postman 测试 Dubbo 服务,Apache Dubbo OpenAPI 即将发布
Apache Dubbo 3.3.3(即将发布)实现了与 OpenAPI 的深度集成,通过与 OpenAPI 的深度集成,用户能够体验到从文档生成到接口调试、测试和优化的全流程自动化支持。不论是减少手动工作量、提升开发效率,还是支持多语言和多环境,Dubbo 3.3.3 都展现了其对开发者体验的极大关注。结合强大的 Mock 数据生成和自动化测试能力,这一版本为开发者提供了极具竞争力的服务治理解决方案。如果你正在寻找高效、易用的微服务框架,Dubbo 3.3.3 将是你不容错过的选择。
934 248
|
运维 Prometheus 监控
如何在测试环境中保持操作系统、浏览器版本和服务器配置的稳定性和一致性?
如何在测试环境中保持操作系统、浏览器版本和服务器配置的稳定性和一致性?
|
Java 测试技术 开发者
必学!Spring Boot 单元测试、Mock 与 TestContainer 的高效使用技巧
【10月更文挑战第18天】 在现代软件开发中,单元测试是保证代码质量的重要手段。Spring Boot提供了强大的测试支持,使得编写和运行测试变得更加简单和高效。本文将深入探讨Spring Boot的单元测试、Mock技术以及TestContainer的高效使用技巧,帮助开发者提升测试效率和代码质量。
1158 2
|
5月前
|
测试技术 Python
Python接口自动化测试中Mock服务的实施。
总结一下,Mock服务在接口自动化测试中的应用,可以让我们拥有更高的灵活度。而Python的 `unittest.mock`库为我们提供强大的支持。只要我们正确使用Mock服务,那么在任何情况下,无论是接口是否可用,都可以进行准确有效的测试。这样,就大大提高了自动化测试的稳定性和可靠性。
259 0
|
Web App开发 JavaScript 前端开发
添加浮动按钮点击滚动到网页底部的纯JavaScript演示代码 IE9、11,Maxthon 1.6.7,Firefox30、31,360极速浏览器7.5.3.308下测试正常
添加浮动按钮点击滚动到网页底部的纯JavaScript演示代码 IE9、11,Maxthon 1.6.7,Firefox30、31,360极速浏览器7.5.3.308下测试正常
|
8月前
|
监控 JavaScript 数据库
Umami:自建网站访问统计服务,突破浏览器广告拦截
本文介绍了开源网站访问统计系统 Umami,一款可替代 Google Analytics 的工具。Umami 支持私有化部署,确保数据完全可控,保护用户隐私。文章详细讲解了 Umami 的部署方式(如 Vercel 云函数、Docker Compose 和 1 Panel)及基本使用方法,包括添加网站和集成跟踪代码。此外,还分享了突破浏览器广告拦截的技巧,例如修改 JS 脚本文件名和服务端接口名称。通过这些优化,可有效避免统计代码被拦截,帮助站长获取更准确的访问数据。
444 0
|
JSON Java 测试技术
SpringCloud2023实战之接口服务测试工具SpringBootTest
SpringBootTest同时集成了JUnit Jupiter、AssertJ、Hamcrest测试辅助库,使得更容易编写但愿测试代码。
413 3
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
1677 1
|
域名解析 缓存 网络协议
浏览器中输入URL返回页面过程(超级详细)、DNS域名解析服务,TCP三次握手、四次挥手
浏览器中输入URL返回页面过程(超级详细)、DNS域名解析服务,TCP三次握手、四次挥手
|
Web App开发 定位技术 iOS开发
Playwright 是一个强大的工具,用于在各种浏览器上测试应用,并模拟真实设备如手机和平板。通过配置 `playwright.devices`,可以轻松模拟不同设备的用户代理、屏幕尺寸、视口等特性。此外,Playwright 还支持模拟地理位置、区域设置、时区、权限(如通知)和配色方案,使测试更加全面和真实。例如,可以在配置文件中设置全局的区域设置和时区,然后在特定测试中进行覆盖。同时,还可以动态更改地理位置和媒体类型,以适应不同的测试需求。
Playwright 是一个强大的工具,用于在各种浏览器上测试应用,并模拟真实设备如手机和平板。通过配置 `playwright.devices`,可以轻松模拟不同设备的用户代理、屏幕尺寸、视口等特性。此外,Playwright 还支持模拟地理位置、区域设置、时区、权限(如通知)和配色方案,使测试更加全面和真实。例如,可以在配置文件中设置全局的区域设置和时区,然后在特定测试中进行覆盖。同时,还可以动态更改地理位置和媒体类型,以适应不同的测试需求。
1005 1