尝试使用Jest侦探和覆盖一个功能,向下降低两个级别。
测试结果说:“预期的模拟函数已被调用,但未被调用。”
// 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: '[email protected]', name: 'Something' }],
to: [{ email: '[email protected]', name: 'Something' }],
subject: 'My Subject',
htmlContent: 'This is test content'
};
await mail.send(testMessage);
expect(sibMock).toHaveBeenCalled();
})
);
mail.send()来自这里...
// 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(为什么需要模拟)...
// 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()的重点。想知道我哪里出错了。
最佳答案
jest.spyOn
替换method on the object it is passed with a spy。
在这种情况下,您传递的sib
表示从sendinblue.js
导出ES6模块,因此Jest
将用间谍替换sibSubmit
的模块出口,并为间谍提供您提供的模拟实现。mail.send
然后调用sibSendTransactionalEmail
,然后直接调用sibSubmit
。
换句话说,不会调用您的间谍,因为sibSendTransactionalEmail
不会调用sibSubmit
的模块导出,而只是直接调用sibSubmit
。
解决此问题的一种简单方法是注意"ES6 modules support cyclic dependencies automatically",因此您可以简单地将模块导入自身,并使用模块导出从sibSubmit
中调用sibSendTransactionalEmail
:
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模块导出,例如works because Jest
transpiles the ES6 modules to Node
modules in a way that allows them to be mutated