【问题标题】:Dart - how to mock a method that returns a futureDart - 如何模拟返回未来的方法
【发布时间】:2014-02-28 01:24:21
【问题描述】:

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

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

      };
    }
    class Album{
      Future<List<Photos>> photos(){
      }
    };

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

我要测试的类看起来有点像

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() 方法。

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

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

【问题讨论】:

    标签: dart dart-async dart-unittest


    【解决方案1】:

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

    这里验证模拟有点棘手,因为您在构造函数中链接期货。稍微了解一下 event loop 在 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);
        }));
      });
    }
    

    【讨论】:

    • 我对我的代码进行了测试,发现使用 thenReturn 时出现错误。 'thenReturn' 不应用于返回 Future。相反,使用 'thenAnswer((_) => future)' 将其更改为 thenAnswer 后它起作用了。
    【解决方案2】:

    这就是我如何做到的

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

    注意:在颤振测试中,我必须像这样将测试包装在 tester.runAsync

          testWidgets(
              'when tapped disables underlying button until future completes',
              (WidgetTester tester) async {
            await tester.runAsync(() async {
               // test here
            });
          });
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-31
      • 2017-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多