模拟服务工作者,可悲的路径测试失败
mock service worker, sad path test failure
最近只是使用 Mock Service Worker 来测试我的 HTTP 请求,我正在寻找测试我的失败路径。
我的第一个测试通过了(很高兴),但是我收到的失败错误是“JSON 输入的意外结束”
它确实按照我想要的方式运行,但从测试的角度来看我有点困惑。
如何让我的失败路径通过测试?
我的测试文件
import "whatwg-fetch";
import { rest } from "msw";
import { setupServer } from "msw/node";
import { collect } from "./collect";
const server = setupServer(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({ base: "stations", clouds: { all: 6 }, cod: 200 })
);
}
)
);
beforeAll(() => server.listen());
afterAll(() => server.close());
afterEach(() => server.resetHandlers());
it("collects data", async () => {
const res = await collect();
expect(res).toEqual({ base: "stations", clouds: { all: 6 }, cod: 200 });
});
it("handles failure", async () => {
server.use(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(ctx.status(401));
}
)
);
await expect(collect()).rejects.toThrow("401");
});
我的获取异步函数
require('dotenv').config()
export const collect = async () => {
const key = process.env.REACT_APP_API_KE
// try{
const res = await fetch(`http://api.openweathermap.org/data/2.5/weather?q=london&appid=${key}`)
if(res.status !== 200){
const error = await res.json()
throw { message: error.message, status: error.cod }
}
const data = await res.json()
return data
}
修复模拟服务器
问题是 collect
函数期望 JSON 响应,即使在出现错误的情况下也是如此,但您的模拟服务器不会 return 响应。因此,当您在 collect
函数中执行 res.json()
时,您会得到一个错误。
将您的响应解析器更新为 return json
响应。
return res(ctx.json({message: "error"}), ctx.status(401));
修复测试
toThrow
在这里不是正确的匹配器,因为 async
函数总是 return promise 而在你的情况下 collect
函数 returns 是一个承诺被抛出的数据拒绝。
因此,您可以改用 toEqual
匹配器。
您还需要更新测试错误的方式。您可以选择以下任何选项:
使用 rejects
匹配器:
it("handles failure", () => {
server.use(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(ctx.json({message: "error"}), ctx.status(401));
}
)
);
return expect(collect()).rejects.toEqual({ message: "error", status: 401 });
});
使用async/await
语法:
it("handles failure", async () => {
server.use(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(ctx.status(401));
}
)
);
try {
await collect();
} catch (err) {
expect(err).toEqual({ message: "error", status: 401 });
}
});
使用.catch
但在这种方法中,您需要明确检查您的 catch
断言是否已被调用,否则已实现的承诺不会使您的测试失败。
it("handles failure", async () => {
server.use(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(ctx.status(401));
}
)
);
expect.assertions(1);
return collect().catch((err) =>
expect(err).toEqual({ message: "error", status: 401 })
);
});
修复 collect
函数
在您的 collect
函数中,status
应该是 res.status
而不是 data.code
。
您还可以通过将 res.json()
调用移出条件语句来稍微清理一下下面的代码。
require("dotenv").config();
export const collect = async () => {
const key = process.env.REACT_APP_API_KEY;
const res = await fetch(
`http://api.openweathermap.org/data/2.5/weather?q=london&appid=${key}`
);
const data = await res.json();
if (res.status !== 200) {
throw { message: data.message, status: res.status };
}
return data;
};
而且你不应该在反应环境变量中存储秘密,那样会暴露。 Docs
在一些帮助下,我更新了我的收集功能,如下所示
我现在发送响应值作为状态
require("dotenv").config();
export const collect = async () => {
const key = process.env.REACT_APP_API_KEY;
const res = await fetch(
`http://api.openweathermap.org/data/2.5/weather?q=london&appid=${key}`
);
const data = await res.json();
if (res.status !== 200) {
throw { message: data.message, status: res.status };
}
return data;
};
我的测试现在看起来像这样,我不得不使用 toEqual 匹配器而不是 toThrow 并使用它 return 而不是 await / async
it("handles failure", () => {
server.use(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(ctx.json({message: "error"}), ctx.status(401));
}
)
);
return expect(collect()).rejects.toEqual({ message: "error", status: 401 });
});
最近只是使用 Mock Service Worker 来测试我的 HTTP 请求,我正在寻找测试我的失败路径。
我的第一个测试通过了(很高兴),但是我收到的失败错误是“JSON 输入的意外结束”
它确实按照我想要的方式运行,但从测试的角度来看我有点困惑。
如何让我的失败路径通过测试?
我的测试文件
import "whatwg-fetch";
import { rest } from "msw";
import { setupServer } from "msw/node";
import { collect } from "./collect";
const server = setupServer(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({ base: "stations", clouds: { all: 6 }, cod: 200 })
);
}
)
);
beforeAll(() => server.listen());
afterAll(() => server.close());
afterEach(() => server.resetHandlers());
it("collects data", async () => {
const res = await collect();
expect(res).toEqual({ base: "stations", clouds: { all: 6 }, cod: 200 });
});
it("handles failure", async () => {
server.use(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(ctx.status(401));
}
)
);
await expect(collect()).rejects.toThrow("401");
});
我的获取异步函数
require('dotenv').config()
export const collect = async () => {
const key = process.env.REACT_APP_API_KE
// try{
const res = await fetch(`http://api.openweathermap.org/data/2.5/weather?q=london&appid=${key}`)
if(res.status !== 200){
const error = await res.json()
throw { message: error.message, status: error.cod }
}
const data = await res.json()
return data
}
修复模拟服务器
问题是 collect
函数期望 JSON 响应,即使在出现错误的情况下也是如此,但您的模拟服务器不会 return 响应。因此,当您在 collect
函数中执行 res.json()
时,您会得到一个错误。
将您的响应解析器更新为 return json
响应。
return res(ctx.json({message: "error"}), ctx.status(401));
修复测试
toThrow
在这里不是正确的匹配器,因为 async
函数总是 return promise 而在你的情况下 collect
函数 returns 是一个承诺被抛出的数据拒绝。
因此,您可以改用 toEqual
匹配器。
您还需要更新测试错误的方式。您可以选择以下任何选项:
使用 rejects
匹配器:
it("handles failure", () => {
server.use(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(ctx.json({message: "error"}), ctx.status(401));
}
)
);
return expect(collect()).rejects.toEqual({ message: "error", status: 401 });
});
使用async/await
语法:
it("handles failure", async () => {
server.use(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(ctx.status(401));
}
)
);
try {
await collect();
} catch (err) {
expect(err).toEqual({ message: "error", status: 401 });
}
});
使用.catch
但在这种方法中,您需要明确检查您的 catch
断言是否已被调用,否则已实现的承诺不会使您的测试失败。
it("handles failure", async () => {
server.use(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(ctx.status(401));
}
)
);
expect.assertions(1);
return collect().catch((err) =>
expect(err).toEqual({ message: "error", status: 401 })
);
});
修复 collect
函数
在您的 collect
函数中,status
应该是 res.status
而不是 data.code
。
您还可以通过将 res.json()
调用移出条件语句来稍微清理一下下面的代码。
require("dotenv").config();
export const collect = async () => {
const key = process.env.REACT_APP_API_KEY;
const res = await fetch(
`http://api.openweathermap.org/data/2.5/weather?q=london&appid=${key}`
);
const data = await res.json();
if (res.status !== 200) {
throw { message: data.message, status: res.status };
}
return data;
};
而且你不应该在反应环境变量中存储秘密,那样会暴露。 Docs
在一些帮助下,我更新了我的收集功能,如下所示 我现在发送响应值作为状态
require("dotenv").config();
export const collect = async () => {
const key = process.env.REACT_APP_API_KEY;
const res = await fetch(
`http://api.openweathermap.org/data/2.5/weather?q=london&appid=${key}`
);
const data = await res.json();
if (res.status !== 200) {
throw { message: data.message, status: res.status };
}
return data;
};
我的测试现在看起来像这样,我不得不使用 toEqual 匹配器而不是 toThrow 并使用它 return 而不是 await / async
it("handles failure", () => {
server.use(
rest.get(
"http://api.openweathermap.org/data/2.5/weather",
(req, res, ctx) => {
return res(ctx.json({message: "error"}), ctx.status(401));
}
)
);
return expect(collect()).rejects.toEqual({ message: "error", status: 401 });
});