如何验证一个方法被一个对象调用,该对象的某些字段可能是 anyObject() 而其他字段具有特定值?

How to verify a method gets called with an object whose some fields may be anyObject() while others have a specific value?

我将 Mockito 与 ScalaTest 一起使用。考虑这个简化的例子。

模型案例class:

case class Batch(batchId: Long, 
                 timestamp: Option[LocalDateTime] = Some(LocalDateTime.now),
                 invoicesReceived: Option[Int])

在我的测试中,我正在模拟一个名为 BatchRepository 的 class,它有一个带有此签名的方法:

def create(conn: Connection, batch: Batch): Long

测试代码相关位:

verify(batchRepository, times(1)).create(anyObject(),
  Batch(anyLong(), anyObject(), Matchers.eq(Some(1))))
)

重点是:我想验证被测代码是否使用任何 Connection 和具有任何 ID 和时间戳的 Batch 实例调用模拟存储库方法,但是 invoicesReceived 正好是 Some(1)

使用 Mockito,这是否可能,如果可能,如何实现?

生产代码创建了一个新的 Batch,它将时间戳设置为当前时刻,因此我认为几乎不可能在 verify() 调用的测试中使用完全相同的时间戳创建真正的 Batch 对象。所以至少对于我需要的时间戳 anyObject().

我尝试了很多变体,比如将整个批次包装在 Matchers.eq() 中,但我还没有找到任何有效的方法:

Invalid use of argument matchers! 2 matchers expected, 4 recorded [...]

如果事实证明有一些替代方法可以使用 Mockito 来测试我想要的东西,我很高兴听到我使用的匹配器完全错误。

(我很难为这个问题写一个好名字;如果你明白我在问什么并且可以更简洁地表达它,请编辑或发表评论。)

问题是您试图同时 verify 两个调用 - createBatch.apply。不能那样做。

做你想做的一种方法是 ArgumentCaptor

val captor = ArgumentCaptor.forClass(classOf[Batch])
verify(batchRepository).create(any(), captor.capture)
captor.getValue should matchPattern {
  case Batch(_, _, Some(1)) => 
}
// or just `captor.getValue.infoReceived shouldBe Some(1)`

你试过mockito-scala了吗?它支持部分函数作为匹配器,所以你可以只写

verify(batchRepository, times(1)).create(any, argMatching({case Batch(_, _, Some(1)) => }))

如果您使用惯用的语法甚至更好

batchRepository.create(*, argMatching({case Batch(_, _, Some(1)) => })) was called