Javascript 在函数(类级别)邮戳之外创建的模拟变量上进行Jest测试上下文/间谍
我试图开玩笑地做一些测试,但却被一个模拟/间谍卡住了。我已经设法让测试工作,但只是通过改变我的实现(这让我感到肮脏) 以下是测试:Javascript 在函数(类级别)邮戳之外创建的模拟变量上进行Jest测试上下文/间谍,javascript,unit-testing,testing,mocking,jestjs,Javascript,Unit Testing,Testing,Mocking,Jestjs,我试图开玩笑地做一些测试,但却被一个模拟/间谍卡住了。我已经设法让测试工作,但只是通过改变我的实现(这让我感到肮脏) 以下是测试: import * as postmark from 'postmark'; jest.mock('postmark'); const mockGetServers = jest.fn(); const AccountClient = jest.fn(() => { return { getServers: mockGetServers };
import * as postmark from 'postmark';
jest.mock('postmark');
const mockGetServers = jest.fn();
const AccountClient = jest.fn(() => {
return {
getServers: mockGetServers
};
});
postmark.AccountClient = AccountClient;
import accountApi from './account-api';
describe('account-api', () => {
describe('listServers', () => {
it('calls postmark listServers', async () => {
await accountApi.listServers();
expect(mockGetServers).toHaveBeenCalledTimes(1);
});
});
});
以下是工作实现:
import * as postmark from 'postmark';
const accountToken = 'some-token-number';
const listServers = async () => {
try {
const accountClient = postmark.AccountClient(accountToken);
const servers = await accountClient.getServers();
return servers;
} catch (e) {
console.log('ERROR', e);
}
};
export default {
listServers
}
import * as postmark from 'postmark';
const accountToken = 'some-token-number';
const accountClient = postmark.AccountClient(accountToken);
const listServers = async () => {
try {
const servers = await accountClient.getServers();
return servers;
} catch (e) {
console.log('ERROR', e);
}
};
export default {
listServers
}
以下是原始实现:
import * as postmark from 'postmark';
const accountToken = 'some-token-number';
const listServers = async () => {
try {
const accountClient = postmark.AccountClient(accountToken);
const servers = await accountClient.getServers();
return servers;
} catch (e) {
console.log('ERROR', e);
}
};
export default {
listServers
}
import * as postmark from 'postmark';
const accountToken = 'some-token-number';
const accountClient = postmark.AccountClient(accountToken);
const listServers = async () => {
try {
const servers = await accountClient.getServers();
return servers;
} catch (e) {
console.log('ERROR', e);
}
};
export default {
listServers
}
唯一的更改是在代码中创建accountClient的位置(在listServers函数内部或外部)。最初的实现将完成,jest将报告没有调用mock
我很困惑,为什么一开始这不起作用,我猜这和模拟的上下文有关。我是不是遗漏了一些笑话在幕后运作的方式?由于accountApi的实现将有更多的函数都使用同一个客户机,因此为所有函数而不是每个函数创建一个函数是有意义的。按函数创建它并不适合我
我创建accountClient的方式有什么不同,这意味着可以在测试中监视模拟?是否有一种方法可以模拟(并监视)在类级别而不是在函数级别创建的对象?
谢谢我想你可能想看看 注意,我没有测试这个实现;可能需要调整 我是不是遗漏了一些笑话在幕后运作的方式 有两点需要注意:
import
调用babeljest
将调用提升到jest.mock
(首先包括块中的任何ES6import
调用)我创建accountClient的方式有什么不同,这意味着可以在测试中监视模拟 在这两种情况下,都会首先运行:
jest.mock('postmark');
…这将自动模拟邮戳
模块
然后运行:
import accountApi from './account-api';
const accountClient = postmark.AccountClient(accountToken);
const servers = await accountClient.getServers();
在原始实现中此行运行:
const accountClient = postmark.AccountClient(accountToken);
await accountApi.listServers();
…它捕获调用邮戳.AccountClient的结果,并将其保存在AccountClient
中。postmark
的自动模拟将使用返回undefined
的模拟函数将AccountClient
存根,因此AccountClient
将设置为undefined
在这两种情况下,测试代码现在开始运行,为邮戳.AccountClient
设置模拟
然后,在测试过程中,该生产线运行:
const accountClient = postmark.AccountClient(accountToken);
await accountApi.listServers();
在原始实现中该调用最终运行以下命令:
const servers = await accountClient.getServers();
…由于accountClient
未定义,因此将下降到catch
,并记录错误,测试将继续,直到在此行失败:
expect(mockGetServers).toHaveBeenCalledTimes(1);
…因为从未调用过mockGetServers
另一方面,在工作实现中运行:
import accountApi from './account-api';
const accountClient = postmark.AccountClient(accountToken);
const servers = await accountClient.getServers();
…由于邮戳在这一点上是模拟的,所以它使用模拟并通过测试
有没有一种方法可以模拟(和监视)在类级别而不是函数级别创建的对象 对 因为原始实现会在导入后立即捕获调用
邮戳.AccountClient
的结果,所以在导入原始实现之前,您只需确保已设置模拟
最简单的方法之一是,在调用jest.mock
时,使用a设置mock,因为它首先被提升并运行
下面是一个更新的测试,可与原始实现一起使用:
import * as postmark from 'postmark';
jest.mock('postmark', () => { // use a module factory
const mockGetServers = jest.fn();
const AccountClient = jest.fn(() => {
return {
getServers: mockGetServers // NOTE: this returns the same mockGetServers every time
};
});
return {
AccountClient
}
});
import accountApi from './account-api';
describe('account-api', () => {
describe('listServers', () => {
it('calls postmark listServers', async () => {
await accountApi.listServers();
const mockGetServers = postmark.AccountClient().getServers; // get mockGetServers
expect(mockGetServers).toHaveBeenCalledTimes(1); // Success!
});
});
});
谢谢,有人向我提到过proxyquire,但我认为这个问题不需要进一步的重要回答。现在明白了。谢谢laddo@brian