Mocktail封装stub方法报No method stub was called from when()错误
问题背景
我正在使用 mocktail 0.3.0 包测试HttpAdapter类的request()方法,该方法会调用http包中Client类的post()方法。
初始业务代码如下:
import 'dart:io'; import 'package:http/http.dart'; class HttpAdapter { static const headers = { HttpHeaders.contentTypeHeader: 'application/json', HttpHeaders.acceptHeader: 'application/json', }; final Client client; HttpAdapter(this.client); Future<void> request({ required String url, required String method, HttpClientBody? body, }) async { await client.post(Uri.parse(url), headers: HttpAdapter.headers); } } class ClientSpy extends Mock implements Client { void mockPost(String url) { when(() => post( Uri.parse(url), headers: any(named: 'headers'), )).thenAnswer( (_) async => Response('{}', HttpStatus.ok), ); } }
直接在测试中编写when打桩逻辑时,用例可正常运行:
void main() { test('Should call post() with correct parameters', () async { // Arrange final client = ClientSpy(); final sut = HttpAdapter(client); when(() => client.post( Uri.parse(url), headers: HttpAdapter.headers, )).thenAnswer( (_) async => Response('{}', HttpStatus.ok), ); // Act await sut.request(url: url, method: method); // Assert verify(() => client.post( Uri.parse(url), headers: HttpAdapter.headers, )); }); }
但将when()打桩语句封装为mockPost()方法调用时,测试会抛出错误:
Bad state: No method stub was called from within 'when()'. Was a real method called, or perhaps an extension method?
对应报错的测试代码如下:
void main() { test('Should call post() with correct parameters', () async { // Arrange final client = ClientSpy(); final sut = HttpAdapter(client); client.mockPost(); // Act await sut.request(url: url, method: method); // Assert verify(() => client.post( Uri.parse(url), headers: HttpAdapter.headers, )); }); }
错误原因
代码存在两个核心问题:
- 方法调用绑定错误:http包自带顶层
post()函数,在ClientSpy的mockPost方法中直接写post(...)时,Dart会优先解析为调用http包的顶层真实网络请求方法,而非当前mock实例的post()实例方法。mocktail依赖拦截mock实例的方法调用来完成打桩,真实方法调用不会被拦截,因此抛出No method stub was called错误。 - 参数缺失:
mockPost方法定义了必填的String url参数,但测试中调用client.mockPost()时未传入该参数,本身不符合方法调用要求。
修复方案
- 修改
ClientSpy的打桩逻辑,给被mock的post方法加上this.前缀,强制指定调用当前mock实例的方法:
class ClientSpy extends Mock implements Client { void mockPost(String url) { // 增加this.前缀,避免误调用顶层post函数 when(() => this.post( Uri.parse(url), headers: any(named: 'headers'), )).thenAnswer( (_) async => Response('{}', HttpStatus.ok), ); } }
- 测试中调用
mockPost时,传入对应的测试url参数:
void main() { // 提前定义测试常量 const testUrl = 'https://example.com/test'; const testMethod = 'post'; test('Should call post() with correct parameters', () async { // Arrange final client = ClientSpy(); final sut = HttpAdapter(client); // 传入必填的url参数 client.mockPost(testUrl); // Act await sut.request(url: testUrl, method: testMethod); // Assert verify(() => client.post( Uri.parse(testUrl), headers: HttpAdapter.headers, )); }); }
修改后测试即可正常运行。
内容的提问来源于stack exchange,提问作者Eyder Rios
相关产品推荐
相关产品推荐

