![](/img/trans.png)
[英]In Dart, how to pass a function as parameter that returns a Future
[英]Dart - how to mock a method that returns a future
我有一個 class,它定義了一個返回 Future 的方法。 Future 包含一個 class 的列表,它也返回一個 future。
class User{
Future<List<Album>> albums(){
};
}
class Album{
Future<List<Photos>> photos(){
}
};
在測試另一個 class 時模擬這些類中的方法的最佳方法是什么?
我正在嘗試測試的 class 看起來有點像
class Presenter {
Presenter( User user){
user.albums().then( _processAlbums);
}
_processAlbums(List<Album> albums) {
albums.forEach( (album)=>album.photos.then( _processPhotos));
}
_processPhotos(List<Photo> photos) {
....stuff
}
}
我試着寫這樣的單元測試
class MockUser extends Mock implements User{}
class MockAlbum extends Mock implements Album{}
class MockPhoto extends Mock implements Photo{}
class MockFutureList<T> extends Mock implements Future<T>{
MockFutureList( List<T> items){
when( callsTo( "then")).thenReturn( items);
}
}
void main(){
test("constuctor should request the albums from the user ",(){
MockUser user = new MockUser();
MockAlbum album = new MockAlbum();
List<Album> listOfAlbums = [ album];
MockPhoto photo = new MockPhoto();
List<Album> listOfPhotos = [ album];
user.when( callsTo( "albums")).thenReturn( new MockFutureList(listOfAlbums));
album.when( callsTo( "photos")).thenReturn( new MockFutureList( listOfPhotos));
PicasaPhotoPresentor underTest = new PicasaPhotoPresentor( view, user);
user.getLogs( callsTo( "albums")).verify( happenedOnce);
album.getLogs( callsTo( "photos")).verify( happenedOnce);
});
}
這使我能夠測試構造函數調用了 user.photos() 方法,但沒有測試調用了 album.photos() 方法。
我不確定 mocking 一個 Future 是個好主意——創建一個包含模擬列表的“真實”Future 不是更好嗎?
任何想法都會非常有幫助!
由於您只想驗證User
和Album
中的方法是否被調用,因此您無需模擬Future
。
驗證模擬在這里有點棘手,因為你在構造函數中鏈接了未來。 通過稍微了解事件循環在Dart中的工作原理,我建議您在創建演示者后使用future並調用expectAsync
。
expectAsync
函數告訴單元測試庫等待它被調用以驗證您的測試。 否則測試將成功完成,而不會滿足您的期望。
有了這個,這就是你的測試應該是這樣的:
import 'package:unittest/unittest.dart';
class MockUser extends Mock implements User {}
class MockAlbum extends Mock implements Album {}
void main() {
test("constuctor should request the albums from the user ", () {
var user = new MockUser();
var album = new MockAlbum();
user.when(callsTo("albums")).thenReturn(new Future(() => [album]));
var presenter = new PicasaPhotoPresentor(view, user);
// Verify the mocks on the next event loop.
new Future(expectAsync(() {
album.getLogs(callsTo("photos")).verify(happendOnce);
}));
});
}
以下是我設法做到的方法
1)定義FutureCallbackMock
class FutureCallbackMock extends Mock implements Function {
Future<void> call();
}
2)從模擬中獲取函數並進行設置
FutureCallback onPressed = FutureCallbackMock().call;
completer = Completer<void>();
future = completer.future;
when(onPressed()).thenAnswer((_) => future);
3)驗證如此
verify(onPressed()).called(1);
4)如果需要,完成未來:
completer.complete();
注意:在flutter測試中,我必須將測試包裝在tester.runAsync
就像這樣
testWidgets(
'when tapped disables underlying button until future completes',
(WidgetTester tester) async {
await tester.runAsync(() async {
// test here
});
});
我能夠使用Mocktail做到這一點。 這是本文的來源,並解釋了如何將其集成到您的應用程序中。 這是一個完整的小部件測試,取決於這個要點代碼。
關鍵是你需要聲明一個 Mock class 有一個call
方法。 然后,您可以模擬返回Future
的頂級 function。 您可以使用when
和verify
方法。
//Gist code
import 'package:gist/main.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter/material.dart';
class LaunchMock extends Mock {
Future<bool> call(
Uri url, {
LaunchMode? mode,
WebViewConfiguration? webViewConfiguration,
String? webOnlyWindowName,
});
}
void main() {
testWidgets('Test Url Launch', (tester) async {
//These allow default values
registerFallbackValue(LaunchMode.platformDefault);
registerFallbackValue(const WebViewConfiguration());
//Create the mock
final mock = LaunchMock();
when(() => mock(
flutterDevUri,
mode: any(named: 'mode'),
webViewConfiguration: any(named: 'webViewConfiguration'),
webOnlyWindowName: any(named: 'webOnlyWindowName'),
)).thenAnswer((_) async => true);
final builder = compose()
//Replace the launch function with a mock
..addSingletonService<LaunchUrl>(mock);
await tester.pumpWidget(
builder.toContainer()<MyApp>(),
);
//Tap the icon
await tester.tap(
find.byIcon(Icons.favorite),
);
await tester.pumpAndSettle();
verify(() => mock(flutterDevUri)).called(1);
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.