You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala+Mockito:如何Mock方法内部调用的方法返回结果?

解决Scala+Mockito测试中getHotels方法未被Mock的问题

你遇到的问题核心是Mock对象搞错了,还混用了测试框架,导致getHotels没有被正确Stub,所以实际调用了真实方法。咱们一步步捋清楚问题,再给出修正方案:

先说说你测试代码里的几个问题

  1. 混用了ScalaMock和Mockito:你同时继承了MockFactory(ScalaMock特性)和用了Mockito的@Mock、@InjectMocks,这俩框架的Mock机制不一样,会互相干扰,选一个用就行,这里咱们就用Mockito。
  2. Mock错了对象:你要Mock的是HotelsService依赖的HotelsServiceInt接口,而不是HotelsService本身!因为HotelsService的getHotels方法是直接转发给hotelsServiceInt的,你MockHotelsService的getHotels根本没用,实际代码调用的是成员变量hotelsServiceInt的方法。
  3. 返回值类型不匹配:HotelsServiceInt的getHotels返回的是Observable<List<String>>,但你直接Stub返回了List,类型不对,Mockito没法正确识别这个Stub。
  4. 初始化逻辑混乱:你手动new了hotelsServiceInjectedMock,又用MockitoAnnotations.initMocks(this),这俩方式冲突,要么用注解注入,要么手动构造实例。

修正后的测试代码

咱们重新写一个正确的测试类,用纯Mockito来实现:

import org.mockito._
import org.mockito.Mockito._
import org.scalatest.{BeforeAndAfter, FunSpec}
import rx.Observable
import java.util.ArrayList

class HotelsServiceSpec extends FunSpec with BeforeAndAfter {
  // 要Mock的是依赖的接口HotelsServiceInt
  @Mock
  private var hotelsServiceIntMock: HotelsServiceInt = _
  
  // 待测试的对象,手动传入Mock的依赖(或者用@InjectMocks也可以)
  private var hotelsService: HotelsService = _

  before {
    // 初始化Mockito的Mock对象
    MockitoAnnotations.initMocks(this)
    // 手动构造待测试对象,把Mock的接口传进去
    hotelsService = new HotelsService(hotelsServiceIntMock)
  }

  describe("HotelsService doSomeBusinessLogic") {
    it("Should return false when hotels meet certain condition") {
      val val1 = 1L
      val val2 = 2L
      
      // 构造测试用的酒店列表,并包装成Observable(因为原方法返回Observable)
      val testHotels = new ArrayList[String]()
      testHotels.add("Hilton")
      testHotels.add("Sheraton")
      testHotels.add("Rotana")
      
      // Stub HotelsServiceInt的getHotels方法,返回我们构造的Observable
      doReturn(Observable.just(testHotels))
        .when(hotelsServiceIntMock)
        .getHotels(Matchers.anyLong(), Matchers.anyLong())

      // 执行待测试方法
      val result = hotelsService.doSomeBusinessLogic(val1, val2)
      
      // 验证结果
      assert(result == false)
      
      // 可选:验证Mock方法被调用了一次
      verify(hotelsServiceIntMock, times(1)).getHotels(val1, val2)
    }
  }
}

关键修正点解释

  • 只使用Mockito:去掉了ScalaMock的MockFactory,避免框架冲突。
  • Mock正确的依赖:现在Mock的是HotelsServiceInt接口,这才是HotelsService真正依赖的对象,Stub它的getHotels方法才能拦截实际调用。
  • 匹配返回值类型:用Observable.just(testHotels)把列表包装成Observable,和原方法的返回类型一致。
  • 清晰的初始化逻辑:先初始化Mock对象,再手动构造待测试的HotelsService,把Mock依赖传进去,逻辑更清晰,也避免了注解注入的潜在问题。

这样修改后,当你运行测试时,doSomeBusinessLogic里调用getHotels就会触发我们Stub的Mock返回,不会再调用真实的HotelsServiceInt实现了。

内容的提问来源于stack exchange,提问作者Ababneh A

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:59:03