测试

编辑

测试是应用程序开发中最重要的部分之一。客户端在测试方面非常灵活,并且与大多数测试框架(例如 ava,以下示例中使用)兼容。

如果您正在使用此客户端,那么您很可能正在使用 Elasticsearch,而您面临的首要问题之一是如何测试您的应用程序。一个完全有效的解决方案是使用真实的 Elasticsearch 实例来测试您的应用程序,但您将进行集成测试,而您想要的是单元测试。有很多方法可以解决这个问题,您可以使用 Docker 创建数据库,或者使用内存兼容的数据库,但是如果您正在编写可以轻松并行化的单元测试,这将变得非常不方便。在进行单元测试时,提高测试体验的另一种方法是使用模拟。

该客户端的设计易于扩展和适应您的需求。由于其内部架构,它允许您更改某些特定的组件,同时保持其余组件的正常运行。每个 Elasticsearch 官方客户端都由以下组件组成:

  • API 层:您可以调用的每个 Elasticsearch API。
  • 传输:一个负责在发送请求之前准备请求并处理所有重试和嗅探策略的组件。
  • 连接池:Elasticsearch 是一个集群,可能具有多个节点,连接池负责处理这些节点。
  • 序列化器:一个包含所有序列化策略的类,从基本的 JSON 到新的行分隔 JSON。
  • 连接:实际的 HTTP 库。

使用官方客户端模拟 Elasticsearch 的最佳方法是替换 连接 组件,因为它承担的责任很少,并且除了获取请求和返回响应外,不与其他内部组件交互。

@elastic/elasticsearch-mock

编辑

每次为您的测试编写模拟可能会很烦人且容易出错,因此我们构建了一个简单而强大的模拟库,专门为该客户端设计,您可以使用以下命令安装它:

npm install @elastic/elasticsearch-mock --save-dev

使用此库,您可以为您发送到 Elasticsearch 的任何请求创建自定义模拟。它提供了一个简单直观的 API,并且仅模拟 HTTP 层,使客户端的其余部分像往常一样工作。

在展示其所有功能以及您可以使用它做什么之前,让我们看一个示例

const { Client } = require('@elastic/elasticsearch')
const Mock = require('@elastic/elasticsearch-mock')

const mock = new Mock()
const client = new Client({
  cloud: { id: '<cloud-id>' },
  auth: { apiKey: 'base64EncodedKey' },
  Connection: mock.getConnection()
})

mock.add({
  method: 'GET',
  path: '/'
}, () => {
  return { status: 'ok' }
})

client.info().then(console.log, console.log)

正如您所见,它与客户端本身紧密合作,一旦您创建了模拟库的新实例,您只需要调用 mock.getConnection() 方法,并将其结果传递给客户端的 Connection 选项。从现在开始,每个请求都由模拟库处理,HTTP 层将永远不会被触及。因此,您的测试速度明显更快,并且您可以轻松地并行化它们!

该库允许您编写“严格”和“宽松”的模拟,这意味着您可以编写一个处理非常特定请求的模拟,或者更宽松地处理一组请求,让我们看看实际效果

mock.add({
  method: 'POST',
  path: '/indexName/_search'
}, () => {
  return {
    hits: {
      total: { value: 1, relation: 'eq' },
      hits: [{ _source: { baz: 'faz' } }]
    }
  }
})

mock.add({
  method: 'POST',
  path: '/indexName/_search',
  body: { query: { match: { foo: 'bar' } } }
}, () => {
  return {
    hits: {
      total: { value: 0, relation: 'eq' },
      hits: []
    }
  }
})

在上面的示例中,每个搜索请求都会获得第一个响应,而每个使用第二个模拟中描述的查询的搜索请求都会获得第二个响应。

您还可以指定动态路径

mock.add({
  method: 'GET',
  path: '/:index/_count'
}, () => {
  return { count: 42 }
})

client.count({ index: 'foo' }).then(console.log, console.log) // => { count: 42 }
client.count({ index: 'bar' }).then(console.log, console.log) // => { count: 42 }

也支持通配符。

另一个非常有趣的用例是能够创建一个随机失败的测试,以查看您的代码如何对故障做出反应

mock.add({
  method: 'GET',
  path: '/:index/_count'
}, () => {
  if (Math.random() > 0.8) {
    return ResponseError({ body: {}, statusCode: 500 })
  } else {
    return { count: 42 }
  }
})

我们已经了解了模拟 Elasticsearch 和测试您的应用程序是多么简单,您可以在 模块文档中找到更多功能和示例。