We all know that mocks are used to solve the closed-loop debugging or testing of front-end development, where the real server API is not developed and only the interface documentation is available. Mock schemes can be placed either on the server side or locally.
The mock on the server side usually requires a special mock service to be enabled for interface configuration and cross-domain.
Native mock schemes are much more flexible. The simplest way is to inject mock data directly into the variable that accepts the return value of the request. However, it has the disadvantages of being too intrusive, not flexible enough, and even polluting the business logic. A slightly more complex solution, such as mock.js, can intercept Ajax by modifying the default behavior of XmlHttpRequest, which solves the problem of constructing random mocks and being too intrusive. However, its disadvantages are equally obvious: the relevant code needs to be removed during real concatenation, and it has no control over fetch elements.
It’s also easy to mock business code without invading it. At present, front-end projects are all engineering, and most of them will use a local Node service, such as Webpack-dev-server, etc. Before we debug the web page with the server, all the content we see is static response provided by the local service. Before the API is completed, even if we use proxy, we can not effectively self-test around the cross-domain. We can start with this local service and mock it by implementing a middleware that intercepts HTTP requests and then performs custom response processing on API-type requests. This mock scheme allows zero intrusion into business code by simply turning off the mock switch or removing the middleware.
Most front-end project native services rely on Express, for example, to implement a middleware. The key issue here is how urls are mapped, and there are two options:
File mapping
File mapping refers to the substitution of “/” in the request URL. For example, a request such as API/A/B can be mapped to a file named API_a_b, which the middleware reads in response to the request.
The map mapping
Map Mapping refers to the configuration of a JSON file instead of a strict format. The key indicates the URL and the value indicates the response content to be returned.
The advantage of file mapping is that there is no special configuration, just create a new mapping file for new requests, but the disadvantage is also obvious, because the file name is static, this method is difficult to handle API/A/B /10 with pathParam GET requests, and the file cannot be reused. Even if two different requests return the same result, you need to create separate mock files. In contrast, the map mapping approach can be quite flexible and mocks can be reused, in addition to the necessary route configuration.
Here is a piece of middleware I wrote called dynamic-mock-Express, which has the following functions and features:
2. Customize URL filtering rules to determine which requests do not need mock 3. Supports setting the value of a map map to a function, and accepts query, Params, and Body 4 of the corresponding request as parameters. It is possible to set any attribute or nested attribute of the return value as a function, and the above parameter 5 can also be accepted. 6. Functions can mock dynamically and responsively by accepting store objects, which can easily simulate real back-end services
Method of use
1. Installation:
npm i dynamic-mock-express -D
Copy the code
2. Create a mock folder in the root directory. Create the index.js configuration file under the mock folder, for example:
// index.js
module.exports = {
needMock: true.// Whether to enable mock. The default value is true and the value is set to false
prefix: "api".// The URL prefix for the mock is required
tip: true.// The console will warn if the url is not matched. The default is true
ignore: (url, method) = > {
// Methods that accept urls and requests and return true will be filtered and not mock
},
routes: {
"GET:a/c": require("./mock_1"),
"GET:a/b/:id": (data) = > { // Params can be accepted. Data has four attributes: params, query, body, and store
return {
data: "mock_2".params: data.params,
};
},
"GET:b/:id/:code": ({params}) = > { // Return the request as is
return {
id: params.id,
code: params.code
}
},
"POST:b/c": { // We can define value as a JSON object directly
a:1
},
"POST:a/b/c": data= > { // With data.body you can take the POST data itself as a response
return {
status: true.body: data.body
};
},
"DELETE:a/b/:id": (data) = > { // Support Restful apis
return {
id: data.params.id
};
},
"DELETE:a/b/c/:id": { // Support attributes or nested attributes defined as functions
a: {
b: 1.c: (data) = > {
return {
id: data.params.id
}
}
}
}
}
};
Copy the code
3. Mount the middleware
Express service
const app = express();
const mock = require("dynamic-mock-express");
app.use(
mock({
mockDir: path.resolve(__dirname, ".. /mock")}));Copy the code
Encapsulated Express services, such as webpack-dev-server (vue-CLI or create-react-app)
const mock = require("dynamic-mock-express");
new WebpackDevServer(compiler, {
...
setup: (app) = > {
app.use(
mock({
mockDir: path.resolve(__dirname, ".. /mock"), // Mock folder directory
entry: "index.js" // Mock folder entry. If the configuration file is called index.js, you can leave it out})); }}Copy the code
If an API/A /b/10 GET request is issued, the mock will respond with the following configuration:
{
data: "mock_2".params: {
id: "10"}}Copy the code
4. Reactive dynamic mocks
Configure the storePath attribute to make mocks responsive, as follows:
const path = require("path");
module.exports = {
needMock: true.prefix: "api".storePath: Path.reslove(__dirname, "store"), // Must be an absolute path
tip: true.routes: {
"GET:a/b/:id": ({store, params}) = > {
return store.data.find(item= > {return item.id == params.id});
},
"POST:a/b": ({store, body}) = > {
store.data.find(item= > {
return item.id == body.id
}).name = body.name;
return {
status: true}; }}}Copy the code
mock/store.js
module.exports = {
data: [{id: 10.name: "zhangsan"
},
{
id: 11.name: "lisi"}}]Copy the code
Use pseudocode to make the following request:
// pseudocode
get("api/a/b/10").then(res= > {
console.log(res) // {id: 10, name: "zhangsan"}
post("api/a/b")
.send({id: 10.name: "wangwu"})
.then(res= > {
get("api/a/b/10").then(res= >{
console.log(res) // {id: 10, name: "wangwu"}})})})Copy the code
You can see that the post changes the data and then gets it again, so you can simulate the interaction of calling a real API with some simple logical code without having to mock it manually.
Project address github.com/silentport/… Welcome to make issue.