【问题标题】:How to verify a method gets called with an object whose some fields may be anyObject() while others have a specific value?如何验证一个方法是否被一个对象调用,该对象的某些字段可能是 anyObject() 而其他字段具有特定值?
【发布时间】:2018-11-20 10:49:43
【问题描述】:

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

模型案例类:

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

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

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

相关测试代码:

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

牛肉是:我想验证被测代码是否使用任何 Connection 和一个具有任何 id 和时间戳的 Batch 实例调用模拟存储库方法,但 invoicesReceived 恰好是 @ 987654325@。

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

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

我尝试了很多变体,例如将整个 Batch 包装在 Matchers.eq() 中,但我没有找到任何可行的方法:

参数匹配器的使用无效!预计 2 个匹配器,4 个记录 [...]

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

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

【问题讨论】:

    标签: scala unit-testing mockito scalatest hamcrest


    【解决方案1】:

    问题是您正试图同时进行两个呼叫 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)`
    

    【讨论】:

    • 太棒了,谢谢!我使用的是FunSuite,所以should matchPattern 似乎不可用,但captor.getValue match 然后case _ => fail 似乎足够干净。
    • 为什么你一直回复any 的答案在我的情况下无法编译?拥有一个对我和未来的读者真正工作的版本不是更有用吗? (any 产生“多态表达式无法实例化为预期类型”;any() 有效。)
    • 只需混入Matchers 即可让matchPattern 工作。至于没有括号的any,我想,你是对的......原来我的代码库中有一个解决方法:def any[T] = Matchers.any() 这么久了,我忘了它:) 我正在恢复它,因为我没有'不喜欢别人不问就编辑我的东西。
    【解决方案2】:

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

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

    如果你使用惯用语法甚至更好

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

    【讨论】:

      猜你喜欢
      • 2013-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-06
      • 2022-12-14
      • 2015-03-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多