嘲笑单元测试以监视较低级别的方法(NodeJS) [英] Jest unit test to spy on lower-level method (NodeJS)
问题描述
尝试使用Jest侦探和覆盖一个向下两级的功能.
Trying to spy and override a function two levels down using Jest.
测试结果显示,预期已调用模拟函数,但尚未调用."
The test results say, "Expected mock function to have been called, but it was not called."
// mail/index.unit.test.js
import mail from './index';
import * as sib from '../sendinblue';
describe('EMAIL Util', () =>
test('should call sibSubmit in server/utils/sendinblue/index.js', async() => {
const sibMock = jest.spyOn(sib, 'sibSubmit');
sibMock.mockImplementation(() => 'Calling sibSubmit()');
const testMessage = {
sender: [{ email: 'foo@example.com', name: 'Something' }],
to: [{ email: 'foo@example.com', name: 'Something' }],
subject: 'My Subject',
htmlContent: 'This is test content'
};
await mail.send(testMessage);
expect(sibMock).toHaveBeenCalled();
})
);
mail.send()来自这里...
mail.send() comes from here...
// mail/index.js
import { sibSendTransactionalEmail } from '../sendinblue';
export default {
send: async message => {
try {
return await sibSendTransactionalEmail(message);
} catch(err) {
console.error(err);
}
}
};
哪个通过axios使用SendInBlue的API(为什么我需要模拟)...
Which uses SendInBlue's API via axios (why I need to mock)...
// sendinblue/index.js
import axios from 'axios';
import config from '../../config/environment';
export async function sibSubmit(method, url, data) {
let instance = axios.create({
baseURL: 'https://api.sendinblue.com',
headers: { 'api-key': config.mail.apiKey }
});
try {
const response = await instance({
method,
url,
data
});
return response;
} catch(err) {
console.error('Error communicating with SendInBlue', instance, err);
}
}
export const sibSendTransactionalEmail = message => sibSubmit('POST', '/v3/smtp/email', message);
我假设mail.send()将在另一个模块中调用sibSendTransactionalEmail(),并且它将调用sibSubmit(),这是jest.spyOn()的重点.想知道我哪里出了错.
I assumed mail.send() would call sibSendTransactionalEmail() in the other module and it would call sibSubmit(), the focus of jest.spyOn(). Wondering where I went wrong.
推荐答案
jest.spyOn
替换在这种情况下,您传递的sib
代表从sendinblue.js
导出的ES6模块,因此Jest
会将sibSubmit
并提供间谍您提供的模拟实现.
In this case you are passing sib
which represents the ES6 module exports from sendinblue.js
, so Jest
will replace the module export for sibSubmit
with the spy and give the spy the mock implementation you provided.
mail.send
然后调用sibSendTransactionalEmail
,然后直接调用sibSubmit
.
mail.send
then calls sibSendTransactionalEmail
which then calls sibSubmit
directly.
换句话说,不会调用您的间谍,因为sibSendTransactionalEmail
不会调用sibSubmit
的模块导出,它只是直接调用sibSubmit
.
In other words, your spy is not called because sibSendTransactionalEmail
does not call the module export for sibSubmit
, it is just calling sibSubmit
directly.
解决此问题的简单方法是注意"ES6模块自动支持循环依赖" ,因此您可以简单地将模块导入自身并使用模块export从sibSendTransactionalEmail
内部调用sibSubmit
:
An easy way to resolve this is to note that "ES6 modules support cyclic dependencies automatically" so you can simply import the module into itself and call sibSubmit
from within sibSendTransactionalEmail
using the module export:
import axios from 'axios';
import config from '../../config/environment';
import * as sib from './'; // import module into itself
export async function sibSubmit(method, url, data) {
let instance = axios.create({
baseURL: 'https://api.sendinblue.com',
headers: { 'api-key': config.mail.apiKey }
});
try {
const response = await instance({
method,
url,
data
});
return response;
} catch(err) {
console.error('Error communicating with SendInBlue', instance, err);
}
}
export const sibSendTransactionalEmail = message => sib.sibSubmit('POST', '/v3/smtp/email', message); // call sibSubmit using the module export
请注意,像这样,用jest.spyOn
替换ES6模块导出是可行的,因为Jest
将ES6模块转换为以下版本中的Node
模块:一种允许他们变异的方式
Note that replacing ES6 module exports with jest.spyOn
like this works because Jest
transpiles the ES6 modules to Node
modules in a way that allows them to be mutated
这篇关于嘲笑单元测试以监视较低级别的方法(NodeJS)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!