测试编辑

测试是应用程序开发过程中最重要的部分之一。该客户端在测试方面非常灵活,并且与大多数测试框架兼容(例如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 和测试您的应用程序是多么简单,您可以在模块文档中找到更多功能和示例。