UnitTest example for asynchronous code

2019-07-14 18:46发布

问题:

After reading the Unit Testing with Dart somehow I'm still can not understand how to use it with Futures.

For example:

void main()
{
    group('database group',(){
    setUp( () {
                // Setup
           });

    tearDown((){
                // TearDown
           });

    test('open connection to local database', (){
        DatabaseBase database = null;

        expect(database = new MongoDatabase("127.0.0.8", "simplechat-db"), isNotNull);

        database.AddMessage(null).then(
            (e) {
                  expectAsync1(e) 
                  {
                     // All ok
                  }
                },
            onError: (err)
                     {
                        expectAsync1(bb)
                        {
                          fail('error !');
                        }
                     }
         );

});

// Add more tests here

}); }

So in the test I create an instance of base abstract class DatabaseBase with some parameters to actual MongoDb class and immediately check if it created. Then I just run some very simple function: AddMessage. This function defined as:

Future AddMessage(String message);

and return completer.future.

If passed message is null then the function will fail completer as: .completeError('Message can not be null');

In actual test I want to test if Future completed successfully or with error. So above this is my try to understand how to test Future returns - the problems is this this test does not fail :(

Could you write in answer a little code example how to test functions that return Future ? And in test I mean - sometimes I want to test return (on success) value and fail test if success value is incorrect and another test should fail then function will fail Future and enter to onError: block.

回答1:

I just re-read your question, and I realize I was answering sort of the wrong question...

I believe you're using expectAsync incorrectly. expectAsync is used to wrap a callback with N parameters and ensure that it ran count times (default 1).

expectAsync will ensure that any exceptions are caught by the test itself and are returned. It does not actually run any expectations by itself (bad nomenclature.)

What you want is just:

database.AddMessage(null).then(
  (value) { /* Don't do anything! No expectations = success! */ },
  onError: (err) { 
    // It's enough to just fail!
    fail('error !');
  }
);

or if you need to ensure that the test completed to some particular value:

database.AddMessage(null).then(
  expectAsync1((value) { /* Check the value in here if you want. */ }),
  onError: (err) { 
    // It's enough to just fail!
    fail('error !');
  }
);

Another way of doing this is to use the completes matcher.

// This will register an asynchronous expectation that will pass if the
// Future completes to a value.
expect(database.AddMessage(null), completes);

or to test for an exception:

// Likewise, but this will only pass if the Future completes to an exception.
expect(database.AddMessage(null), throws);

If you want to check the completed value, you could do as follows:

expect(database.AddMessage(null).then((value) {
  expect(value, isNotNull);
}), completes);

See:

  • http://api.dartlang.org/docs/bleeding_edge/matcher.html#completes
  • http://api.dartlang.org/docs/bleeding_edge/unittest.html#expectAsync0
  • http://www.dartlang.org/articles/dart-unit-tests/#asynchronous-tests


回答2:

A Future can be returned from a test() method - this will cause Unit Test to wait for the Future to complete.

I usually put my expect() calls in a then() callback. For example:

test('foo', () {
  return asyncBar().then(() => expect(value, isTrue));
});