155
votes

I like to simulate an asynchronous web service call in my Dart application for testing. To simulate the randomness of these mock calls responding (possibly out of order) I'd like to program my mocks to wait (sleep) for a certain period of time before returning the 'Future'.

How can I do this?

7

7 Answers

152
votes

You can also use the Future.delayed factory to complete a future after a delay. Here is an example of two functions that return a string asynchronously after a delay:

import 'dart:async';

Future sleep1() {
  return new Future.delayed(const Duration(seconds: 1), () => "1");
}

Future sleep2() {
  return new Future.delayed(const Duration(seconds: 2), () => "2");
}
149
votes

2019 edition:

In Async Code

await Future.delayed(Duration(seconds: 1));

In Sync Code

import 'dart:io';

sleep(Duration(seconds:1));

Note: This blocks the entire process (isolate), so other async functions will not be processed. It's also not available on the web because Javascript is really async-only.

70
votes

It's not always what you want (sometimes you want Future.delayed), but if you really want to sleep in your Dart command-line app, you can use dart:io's sleep():

import 'dart:io';

main() {
  sleep(const Duration(seconds:1));
}
29
votes

I found that there are several implementations in Dart to make the code delay execution:

new Future.delayed(const Duration(seconds: 1)); //recommend

new Timer(const Duration(seconds: 1), ()=>print("1 second later."));

sleep(const Duration(seconds: 1)); //import 'dart:io';

new Stream.periodic(const Duration(seconds: 1), (_) => print("1 second later.")).first.then((_)=>print("Also 1 second later."));
//new Stream.periodic(const Duration(seconds: 1)).first.then((_)=>print("Also 1 second later."));
19
votes

For Dart 2+ syntax , in a async function context:

import 'package:meta/meta.dart'; //for @required annotation

void main() async {
  void justWait({@required int numberOfSeconds}) async {
    await Future.delayed(Duration(seconds: numberOfSeconds));
  }

  await justWait(numberOfSeconds: 5);
} 
5
votes

This a useful mock that can take an optional parameter to mock an error:

  Future _mockService([dynamic error]) {
    return new Future.delayed(const Duration(seconds: 2), () {
      if (error != null) {
        throw error;
      }
    });
  }

You can use it like this:

  await _mockService(new Exception('network error'));
-3
votes

I also needed to wait for a service to complete during a unit test. I implemented this way:

void main()
{
    test('Send packages using isolate', () async {
        await SendingService().execute();
    });
    // Loop to the amount of time the service will take to complete
    for( int seconds = 0; seconds < 10; seconds++ ) {
        test('Waiting 1 second...', () {
            sleep(const Duration(seconds:1));
        } );
    }
}
...
class SendingService {
    Isolate _isolate;
    Future execute() async {
        ...
        final MyMessage msg = new MyMessage(...);
        ...
        Isolate.spawn(_send, msg)
            .then<Null>((Isolate isolate) => _isolate = isolate);
    }
    static void _send(MyMessage msg) {
        final IMyApi api = new IMyApi();
        api.send(msg.data)
            .then((ignored) {
                ...
            })
            .catchError((e) {
                ...
            } );
    }
}