You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为单元测试Mock OpenSearch客户端?

解决OpenSearch客户端Mock的单元测试问题

问题背景

需要Mock OpenSearch域名,对调用它的TypeScript函数做单元测试。现有OpenSearch客户端可正常工作,但Mock时遇到报错:elasticsearch_mock_1.default is not a constructor。

现有客户端代码

import { Client } from '@opensearch-project/opensearch'

const opensearch = new Client({
   ...AwsSigv4Signer({
     region: "us-east-1",
     service: "es",
   }),
   node: process.env.SEARCH_DOMAIN_ENDPOINT
})

尝试的Mock代码及报错

import { Client, Connection } from "@opensearch-project/opensearch"
import Mock from "@elastic/elasticsearch-mock"

describe('test content search handler', function () {
    it('should return list of content when no filter parameters are passed', async function() {
         const openSearchMock = new Mock();
         const opensearch = new Client({
           Connection: openSearchMock.getConnection() as any,
           node: process.env.SEARCH_DOMAIN_ENDPOINT
         });

         openSearchMock.add({
           method: "GET",
           path: "/index/_search"
         }, () => {
            return {
              status: 'ok'
            }
         })
    });
});

运行测试时报错:elasticsearch_mock_1.default is not a constructor


解决方案

方法1:修正@elastic/elasticsearch-mock的导入与使用

报错核心原因是该包的导出方式为命名导出,而非默认导出,需调整导入和实例化方式:

import { Client } from "@opensearch-project/opensearch"
import { createMock } from "@elastic/elasticsearch-mock" // 改为命名导入

describe('test content search handler', function () {
    it('should return list of content when no filter parameters are passed', async function() {
         const openSearchMock = createMock(); // 使用createMock函数创建实例
         const opensearch = new Client({
           Connection: openSearchMock.getConnection(),
           node: process.env.SEARCH_DOMAIN_ENDPOINT
         });

         // 模拟_search接口的返回(建议贴合实际OpenSearch响应结构)
         openSearchMock.add({
           method: "GET",
           path: "/index/_search"
         }, () => {
            return {
              status: 200,
              body: {
                hits: {
                  hits: [{ _source: { id: 1, title: "Mock Content" } }]
                }
              }
            }
         });

         // 执行你的业务函数并断言结果
         const result = await yourSearchLogic(opensearch);
         expect(result).toEqual([{ id: 1, title: "Mock Content" }]);
    });
});

注意:该包为Elasticsearch客户端设计,与OpenSearch客户端可能存在兼容性问题,若仍有异常,建议使用方法2。

方法2:用Jest直接Mock@opensearch-project/opensearch模块

无需额外依赖,直接利用Jest的Mock能力覆盖客户端模块,稳定性更强:

import { Client } from '@opensearch-project/opensearch';
import yourSearchFunction from './your-search-module'; // 导入你的业务函数

// Mock整个OpenSearch客户端模块
jest.mock('@opensearch-project/opensearch', () => {
  // 模拟客户端实例的方法(这里以search为例)
  const mockClient = {
    search: jest.fn()
  };
  return {
    Client: jest.fn(() => mockClient),
    AwsSigv4Signer: jest.fn(() => ({})), // 模拟签名器,避免初始化报错
  };
});

describe('test content search handler', () => {
  it('should return list of content when no filter parameters are passed', async () => {
    // 获取Mock的search方法
    const mockSearch = (Client as jest.Mock).mock.results[0].value.search;
    
    // 预设Mock返回值
    mockSearch.mockResolvedValue({
      body: {
        hits: {
          hits: [
            { _source: { id: 1, title: 'Test Content 1' } },
            { _source: { id: 2, title: 'Test Content 2' } }
          ]
        }
      }
    });

    // 执行业务函数
    const result = await yourSearchFunction();
    
    // 断言search方法被正确调用
    expect(mockSearch).toHaveBeenCalledWith({
      index: 'index',
      body: {} // 替换为你的业务函数实际传入的查询体
    });
    
    // 断言业务函数返回结果符合预期
    expect(result).toEqual([
      { id: 1, title: 'Test Content 1' },
      { id: 2, title: 'Test Content 2' }
    ]);
  });
});

说明:

  • 可根据业务需求,Mocksearch之外的其他OpenSearch方法(如get、index等)
  • 模拟AwsSigv4Signer是为了跳过真实签名逻辑,避免单元测试中的初始化报错

内容的提问来源于stack exchange,提问作者DanHam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 19:10:18