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

如何用Mockito模拟首次调用抛异常、二次调用正常返回的场景?

搞定Mockito异步方法的重试逻辑测试问题~

你遇到的问题很典型:要测试网络调用的重试逻辑,需要让mock的方法第一次返回错误,第二次返回正常结果。你的思路方向是对的,但因为异步代码的测试细节和Mockito的使用技巧没到位,导致测试抛出异常。下面给你两种靠谱的解决办法:

方法一:用列表按顺序返回不同的Future

这个和你原来的思路一致,但要补上异步测试必须的async/await,不然测试会在Future完成前就结束,错误也没法被重试逻辑处理。调整后的代码如下:

test('验证重试逻辑:首次失败后成功返回', () async {
  var mock = MockHttpClient();
  var responses = [
    Future.error(Exception('boom')),
    Future.value('some return value'),
  ];

  // 每次调用getStuff就取列表里的第一个元素
  when(mock.getStuff()).thenAnswer((_) => responses.removeAt(0));

  var client = Client(inner: mock);
  // 这里一定要await!因为someCall是异步方法,返回Future
  var result = await client.someCall();

  expect(result, 'some return value');
});

这里的关键点:

  • 你的client.someCall()肯定是异步方法(返回Future<String>),测试时必须用await等待它执行完,不然result只是个Future对象,没法和字符串对比
  • responses.removeAt(0)会严格按顺序返回:第一次调用给错误Future,第二次给成功Future,完美匹配重试逻辑的两次调用

方法二:用计数器灵活控制返回结果

如果不想维护列表,用计数器跟踪调用次数会更灵活,比如要测3次失败再成功的场景也很方便:

test('验证重试逻辑:首次失败后成功返回', () async {
  var mock = MockHttpClient();
  var callCount = 0;

  when(mock.getStuff()).thenAnswer((_) {
    callCount++;
    // 第一次调用返回错误,之后都返回成功
    return callCount == 1 
        ? Future.error(Exception('boom')) 
        : Future.value('some return value');
  });

  var client = Client(inner: mock);
  var result = await client.someCall();

  expect(result, 'some return value');
  // 还能验证方法确实被调用了2次,确保重试逻辑生效
  verify(mock.getStuff()).called(2);
});

为啥原来的代码会炸?

你原来的代码没加await,直接把client.someCall()的结果赋值给result,这时候result是个Future<String>,expect直接拿它和字符串比肯定不对。而且Future里的错误因为没被await或者catchError处理,会直接变成未捕获异常,导致测试崩溃。

另外要注意:Mockito的thenThrow是给同步方法用的,如果是返回Future的异步方法,用thenThrow会让方法直接抛出同步异常,这和真实网络调用的异步错误场景不符,所以异步方法的错误返回一定要用thenAnswer返回Future.error,而不是thenThrow。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 12:32:54