fxl*_*ire 5 unit-testing typescript jestjs
我需要模拟依赖项的功能,但仅限于特定的测试用例。在我的其他测试中,我想保持模块不变。我也在嘲笑其他模块。那些需要保持嘲笑。
我尝试了多种方法,因为这个问题的许多变体都被问到了,但是由于我需要在不被嘲笑的情况下使用原始模块,所以其他解决方案似乎都不起作用......
这是我需要的一个例子
// app.ts
import * as moduleA from 'moduleA';
// ...
app.post('/signup', async (req, res) => {
// ...
const hashed = await moduleA.hash(req.body.password);
// ...
});
export default app;
// app.test.ts
// some mocks
jest.mock('./database', () => ({ ... }));
// ...
import * as request from 'supertest';
import app from './app';
// ...
describe('A', () => {
test('Those should work', async () => {
const response = await request(app).post('/signup').send({ password: 'pw' });
expect(response.status).toBe(200);
// ...
});
// many other tests
test('I need to force hash to crash here', async () => {
// mock moduleA.hash only for this test
const response = request(app).post('/signup').send({ password: 'pw' });
expect(response.status).toBe(500);
});
test('moduleA.hash should be back to its default function', async () => {
// request(app) and moduleA.hash will work properly, not mocked
// ./database stays mocked
});
});
Run Code Online (Sandbox Code Playgroud)
您可以使用jest.spyOn()来模拟hash的方法moduleA,并使用.mockRestore()来恢复hash到原始实现。
这是解决方案:
\n\napp.ts:
import express from \'express\';\nimport bodyParser from \'body-parser\';\n\nimport * as moduleA from \'./moduleA\';\nconst app = express();\n\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(bodyParser.json());\n\napp.post(\'/signup\', async (req, res) => {\n try {\n const hashed = await moduleA.hash(req.body.password);\n console.log(hashed);\n res.sendStatus(200);\n } catch (error) {\n res.sendStatus(500);\n }\n});\n\nexport default app;\nRun Code Online (Sandbox Code Playgroud)\n\nmoduleA.ts:
export const hash = async (data: string) => {\n return \'real hashed value\';\n};\nRun Code Online (Sandbox Code Playgroud)\n\napp.spec.ts:
import app from \'./app\';\nimport request from \'supertest\';\nimport * as moduleA from \'./moduleA\';\n\ndescribe(\'app\', () => {\n test(\'Those should work\', async () => {\n const response = await request(app)\n .post(\'/signup\')\n .send({ password: \'pw\' });\n expect(response.status).toBe(200);\n });\n\n test(\'I need to force hash to crash here\', async () => {\n const mockedError = new Error(\'hash error\');\n const hashSpy = jest.spyOn(moduleA, \'hash\').mockRejectedValueOnce(mockedError);\n const response = await request(app)\n .post(\'/signup\')\n .send({ password: \'pw\' });\n expect(response.status).toBe(500);\n expect(moduleA.hash).toBeCalledWith(\'pw\');\n hashSpy.mockRestore();\n });\n\n test(\'moduleA.hash should be back to its default function\', async () => {\n const logSpy = jest.spyOn(console, \'log\');\n const response = await request(app)\n .post(\'/signup\')\n .send({ password: \'pw\' });\n expect(response.status).toBe(200);\n expect(logSpy).toBeCalledWith(\'real hashed value\');\n });\n});\nRun Code Online (Sandbox Code Playgroud)\n\n100%覆盖率的单元测试结果:
\n\nPASS src/stackoverflow/47540126/app.spec.ts\n app\n \xe2\x9c\x93 Those should work (72ms)\n \xe2\x9c\x93 I need to force hash to crash here (10ms)\n \xe2\x9c\x93 moduleA.hash should be back to its default function (14ms)\n\n console.log src/stackoverflow/47540126/app.ts:3569\n real hashed value\n\n console.log node_modules/jest-mock/build/index.js:860\n real hashed value\n\n------------|----------|----------|----------|----------|-------------------|\nFile | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |\n------------|----------|----------|----------|----------|-------------------|\nAll files | 100 | 100 | 100 | 100 | |\n app.ts | 100 | 100 | 100 | 100 | |\n moduleA.ts | 100 | 100 | 100 | 100 | |\n------------|----------|----------|----------|----------|-------------------|\nTest Suites: 1 passed, 1 total\nTests: 3 passed, 3 total\nSnapshots: 0 total\nTime: 4.156s, estimated 5s\nRun Code Online (Sandbox Code Playgroud)\n\n这是完成的演示: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/47540126
\n| 归档时间: |
|
| 查看次数: |
4768 次 |
| 最近记录: |