1

在以前版本的 Elastic4s 中,您可以执行类似的操作

val argument1: ArgumentCapture[DeleteIndexDefinition] = ???
verify(client).execute(argument1.capture())
assert(argument1 == ???)

val argument2: ArgumentCapture[IndexDefinition] = ???
verify(client, times(2)).execute(argument2.capture())
assert(argument2 == ???)

在您的测试中执行了几次之后(即一次DeleteIndexDefinition,随后是两次IndexDefinition)。每个验证都将与其类型匹配。

但是,Elastic4s 现在在其client.execute方法中采用了一个隐式参数。参数是 type Executable[T,R],这意味着您现在需要类似

val argument1: ArgumentCapture[DeleteIndexDefinition] = ???
verify(client).execute(argument1.capture())(any[Executable[DeleteIndexDefinition,R]])
assert(argument1 == ???)

val argument2: ArgumentCapture[IndexDefinition] = ???
verify(client, times(2)).execute(argument2.capture())(any[Executable[IndexDefinition,R]])
assert(argument2 == ???)

这样做之后,我遇到了一个错误。Mockitoclient.execute在第一次验证中考虑了这三个。是的,即使第一个参数是不同的类型。

那是因为隐式(第二个参数)在类型擦除之后具有相同的类型Executable

所以断言失败了。如何在此设置中进行测试?

4

2 回答 2

1

我的解决方案是使用泛型类型创建一个验证。我花了一段时间才意识到,即使没有通用类型,你总是有 AnyRef。

所以,像这样的工作

val objs: ArgumentCaptor[AnyRef] = ArgumentCaptor.forClass(classOf[AnyRef])
verify(client, times(3)).execute(objs.capture())(any())
val values = objs.getAllValues
assert(values.get(0).isInstanceOf[DeleteIndexDefinition])
assert(values.get(1).isInstanceOf[IndexDefinition])
assert(values.get(2).isInstanceOf[IndexDefinition])

我已经创建了问题和答案。但我会考虑其他答案。

于 2015-06-10T17:31:32.427 回答
1

现在在 elastic4s 中采用的封装执行每个请求类型的逻辑的方法是使用typeclasses。这就是为什么隐含现在存在的原因。它有助于模块化每个请求类型,并避免开始潜入 ElasticClient 类的上帝类反模式。

我能想到的两件事可能会对您有所帮助:

  1. 您已经发布的内容,使用 Mockito 并将隐式作为另一个匹配器传递。这就是您可以使用一般隐式模拟方法的方式。

  2. 不使用 mockito,而是建立一个本地嵌入式节点,并针对真实数据进行尝试。这是我编写 elasticsearch 代码时的首选方法。优点是您正在针对真实服务器测试真实查询,因此不仅要检查它们是否被调用,还要检查它们是否确实有效。(有些人可能认为这是一个集成测试,但无论我不同意,它都在一个独立的测试中运行,没有外部部门)。

最新版本的 elastic4s 甚至包括一个测试工具包,可以很容易地获得嵌入式节点。您可以查看几乎所有的单元测试,以了解如何使用它。

于 2015-06-12T01:21:01.597 回答