Javascript 如何强制函数返回值?
我试图测试一些依赖于api返回一些数据的代码。目前,我可以在此函数中模拟ListNamespacedRess的调用:Javascript 如何强制函数返回值?,javascript,node.js,unit-testing,mocking,jestjs,Javascript,Node.js,Unit Testing,Mocking,Jestjs,我试图测试一些依赖于api返回一些数据的代码。目前,我可以在此函数中模拟ListNamespacedRess的调用: async function getIngress(namespace) { try { const result = await k8sIngressApi.listNamespacedIngress(namespace, true); const resultSpec = result.body.items.filter(e => e.metadat
async function getIngress(namespace) {
try {
const result = await k8sIngressApi.listNamespacedIngress(namespace, true);
const resultSpec = result.body.items.filter(e => e.metadata.name === deploymentPrefix)[0];
if (!resultSpec) {
throw new TypeError('Ingress spec is undefined');
}
return resultSpec;
} catch (e) {
return Promise.reject(e);
}
}
使用jest.mock并在此库中模拟该函数的返回值,如下所示:
jest.mock('@kubernetes/client-node', () => ({
KubeConfig: jest.fn().mockImplementation(() => ({
loadFromCluster: jest.fn(),
loadFromDefault: jest.fn(),
makeApiClient: () => ({
listNamespacedIngress: () =>
Promise.resolve({
body: {
items: [
{
metadata: {
name: 'a',
namespace: 'b',
},
spec: {
rules: [
{
host: 'url.com',
http: {
paths: [
{
backend: {
serviceName: 'a',
servicePort: 80,
},
},
],
},
},
],
},
},
这样,如果resultSpec最终没有被定义,我就能够测试初始返回值,如下所示(此测试通过):
但是,我不确定如何强制ListNamespacedRess返回为未定义
编辑:添加了对模块的完全使用
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
const k8sDeploymentApi = kc.makeApiClient(k8s.AppsV1Api);
const k8sServiceApi = kc.makeApiClient(k8s.CoreV1Api);
const k8sIngressApi = kc.makeApiClient(k8s.NetworkingV1beta1Api);
const BRANCH_NAME = process.argv.slice(2)[0].toLowerCase();
const NAMESPACE = 'dev';
const deploymentPrefix = 'storybook-staging';
const DEPLOYMENT_CONFIG = getDeploymentConfig(deploymentPrefix, BRANCH_NAME);
const SERVICE_CONFIG = getServiceConfig(deploymentPrefix, BRANCH_NAME);
const INGRESS_CONFIG = getIngressConfig(deploymentPrefix);
const HTTP_CONFLICT = 409;
process.on('exit', code => {
console.log(`About to exit with code: ${code}`);
});
async function getIngress(namespace) {
try {
const result = await k8sIngressApi.listNamespacedIngress(namespace, true);
console.log(result);
const resultSpec = result.body.items.filter(e => e.metadata.name === deploymentPrefix)[0];
if (!resultSpec) {
throw new TypeError('Ingress spec is undefined');
}
return resultSpec;
} catch (e) {
return Promise.reject(e);
}
}
listNamespacedIngress
更改返回值的正确方法是将其设置为Jest spy。由于它是嵌套的,不能在测试中轻松引用,因此应该在模块模拟之外定义它:
// should be var because jest.mock is hoisted
var mockListNamespacedIngress;
jest.mock('@kubernetes/client-node', () => {
mockListNamespacedIngress = jest.fn();
return {
KubeConfig: jest.fn().mockImplementation(() => ({
loadFromCluster: jest.fn(),
loadFromDefault: jest.fn(),
makeApiClient: () => ({
listNamespacedIngress: mockListNamespacedIngress
...
这还允许断言调用了函数:
mockListNamespacedIngress.mockResolvedValue({ body: { items: [...] } });
await expect(getIngress()).resolves.toEqual('a');
expect(mockListNamespacedIngress).toBeCalledWith(...);
...
mockListNamespacedIngress.mockResolvedValue({ body: { items: [] } });
await expect(getIngress()).rejects.toThrow(TypeError);
expect(mockListNamespacedIngress).toBeCalledWith(...);
事实上,如果我能再问一个问题!当我运行这个程序时,当我试图读取body.items等时,我变得未定义。当我控制台记录result的值时,我得到了这个{[Function:mockConstructor]\u isMockFunction:true,…},所以它似乎返回了模拟对象本身的值,而不是我给它的值?编辑:我似乎还发现mockListNamespacedIngress没有定义,尽管它位于文件的顶部,并且在我的实现mockListNamespacedIngress中被引用。如果在导入时立即调用KubeConfig,可能会出现问题。请用使用KubeConfig的模块更新问题。现在还不清楚定义了getingres的模块与
@kubernetes/client node
之间的关系。后者被嘲笑的方式可能取决于这一点。我明白了<如果代码>kc在单独的模块中实例化,则可以模拟它,而不是模拟整个KubeConfig
。但由于它是在同一个模块中声明和使用的,因此将spy作为MockListNamespacedRess变量公开以访问它更容易。更新了这篇文章。据我所知,没有任何意义。您可以使用`()=>{let mockListNamespacedIngress=jest.fn();返回{mockListNamespacedIngress,KubeConfig:…`并像导入{mockListNamespacedIngress}一样导入模拟模块上的间谍从“@kubernetes/client node”但是使用虚拟导出似乎不适合一次性使用,如果一个mock被存储在\uuumocks\uuuu
中,这将是有意义的。顺便说一句let
而不是var
withjest。mock
应该导致此错误,而不是使mockListNamespacedIngress无声地未定义。Th我能想到的唯一原因是测试被传输到ES5。由于Jest在节点中运行,这可能是不必要的和有害的。如果不需要ES5,请检查Jest配置。
mockListNamespacedIngress.mockResolvedValue({ body: { items: [...] } });
await expect(getIngress()).resolves.toEqual('a');
expect(mockListNamespacedIngress).toBeCalledWith(...);
...
mockListNamespacedIngress.mockResolvedValue({ body: { items: [] } });
await expect(getIngress()).rejects.toThrow(TypeError);
expect(mockListNamespacedIngress).toBeCalledWith(...);