Javascript 如何强制函数返回值?

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

我试图测试一些依赖于api返回一些数据的代码。目前,我可以在此函数中模拟ListNamespacedRess的调用:

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
with
jest。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(...);