如何为单元测试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' } ]); }); });
说明:
- 可根据业务需求,Mock
search之外的其他OpenSearch方法(如get、index等) - 模拟
AwsSigv4Signer是为了跳过真实签名逻辑,避免单元测试中的初始化报错
内容的提问来源于stack exchange,提问作者DanHam
相关产品推荐
相关产品推荐

