ScalaTest:如何统计eventually块内方法的执行次数?
统计ScalaTest Eventually中getItem的调用次数
嘿,要统计Eventually.eventually里getItem(recordId)的调用次数,有几个简单好用的方案,你可以根据自己的测试场景来选:
方案1:用线程安全的原子计数器(通用场景)
如果不确定测试是否涉及多线程操作,用AtomicInteger来计数最稳妥,它能保证计数的准确性:
import java.util.concurrent.atomic.AtomicInteger import org.scalatest.concurrent.Eventually import org.scalatest.time.{Seconds, Span} // 初始化计数器,初始值为0 val callCount = new AtomicInteger(0) // 包装原getItem方法,每次调用时先自增计数器 def trackedGetItem(id: String) = { callCount.incrementAndGet() // 每次调用计数器+1 getItem(id) // 调用原方法并返回结果 } // 在Eventually块中使用包装后的方法 Eventually.eventually( timeout(Span(5, Seconds)), interval(Span(1, Seconds)) ) { trackedGetItem(recordId).record.forall( _.state.contains(Constants.RecordStatusComplete) ) shouldEqual true } // 最终获取总调用次数 println(s"getItem总共被调用了 ${callCount.get()} 次")
这个方案的优点是线程安全,不管Eventually内部是否有线程切换,计数都不会出错,适合绝大多数场景。
方案2:用普通可变变量(单线程场景)
如果你的测试是单线程执行的(ScalaTest的Eventually默认是单线程重试),用普通的var会更轻量,代码也更简洁:
import org.scalatest.concurrent.Eventually import org.scalatest.time.{Seconds, Span} var callCount = 0 // 初始化计数器 def trackedGetItem(id: String) = { callCount += 1 // 每次调用+1 getItem(id) } // 执行Eventually逻辑 Eventually.eventually( timeout(Span(5, Seconds)), interval(Span(1, Seconds)) ) { trackedGetItem(recordId).record.forall( _.state.contains(Constants.RecordStatusComplete) ) shouldEqual true } // 获取调用次数 println(s"getItem调用次数:$callCount")
这个方案省去了原子类的开销,适合确定单线程的测试场景。
方案3:用Mockito验证(已使用Mockito的场景)
如果你的测试已经在使用Mockito做Mock,直接利用Mockito的调用验证功能就能统计次数,还能灵活预设返回值模拟重试过程:
import org.mockito.Mockito._ import org.scalatestplus.mockito.MockitoSugar import org.scalatest.concurrent.Eventually import org.scalatest.time.{Seconds, Span} // 假设getItem是RecordService中的方法,先mock这个服务 val mockRecordService = mock[RecordService] // 预设mock的返回值:模拟前两次返回未完成,第三次返回完成 when(mockRecordService.getItem(recordId)) .thenReturn(Record(Seq(RecordItem(state = Some(Constants.RecordStatusPending))))) .thenReturn(Record(Seq(RecordItem(state = Some(Constants.RecordStatusPending))))) .thenReturn(Record(Seq(RecordItem(state = Some(Constants.RecordStatusComplete))))) // 执行Eventually逻辑 Eventually.eventually( timeout(Span(5, Seconds)), interval(Span(1, Seconds)) ) { mockRecordService.getItem(recordId).record.forall( _.state.contains(Constants.RecordStatusComplete) ) shouldEqual true } // 验证并获取调用次数:这里会验证getItem被调用了3次 verify(mockRecordService, times(3)).getItem(recordId)
这个方案不需要额外写包装方法,Mockito会自动帮你记录调用次数,适合已经在使用Mockito的测试套件。
内容的提问来源于stack exchange,提问作者WDrgn
相关产品推荐
相关产品推荐

