Dart - 如何模拟返回未来的方法

ric*_*ard 5 dart dart-unittest dart-async

我有一个类定义了一个返回 Future 的方法。Future 包含一个类列表,这些类也返回一个未来。

    class User{
      Future<List<Album>> albums(){

      };
    }
    class Album{
      Future<List<Photos>> photos(){
      }
    };
Run Code Online (Sandbox Code Playgroud)

在测试另一个类时模拟这些类中方法的最佳方法是什么?

我试图测试的课程看起来有点像

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
  }
}
Run Code Online (Sandbox Code Playgroud)

我尝试编写这样的单元测试

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);

  });
}
Run Code Online (Sandbox Code Playgroud)

这让我可以测试构造函数是否调用了 user.photos() 方法,而不是调用了专辑.photos() 方法。

我不确定模拟 Future 是一个好主意 - 创建一个包含模拟列表的“真实”未来不是更好吗?

任何想法都会非常有帮助!

小智 6

由于您只对验证UserAlbum调用的方法感兴趣,因此您无需模拟Future.

在这里验证模拟有点棘手,因为您在构造函数中链接期货。稍微了解一下Dart 中事件循环的工作原理,我建议expectAsync在创建演示者后使用 future 和调用。

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);
    }));
  });
}
Run Code Online (Sandbox Code Playgroud)

  • 我对代码进行了测试,发现使用 thenReturn 时出现错误。'thenReturn' 不应该用于返回 Future。相反,使用 'thenAnswer((_) =&gt; future)' 将其更改为 thenAnswer 后它就起作用了。 (2认同)

sur*_*rga 0

你可以这样做:

when(mock.method()).thenAnswer((_) => Future.value('string'));
Run Code Online (Sandbox Code Playgroud)