Ожидание инициализации моего класса (или как ждать завершения Future)?

Фьючерсы на Dart - проклятие моего существования.

У меня есть класс, который вызывает асинхронную (Future) функцию для запуска экземпляра базы данных следующим образом:

class DataManager {
  bool DbIsReady = false;
  Db _db;

  DataManager() {
    init_mongo_db();
  }

  void init_mongo_db() {
    print("Initializing MongoDB");
    _db = new Db("mongodb://127.0.0.1/test");
    _db.open().then((_) {
      DbIsReady = true;
    });
  }  

  Future<List> attemptLogin(String username, String password) {
    users = _db.collection("users");

    return // ... rest of code cut out for clarity
  }
}

Это работает нормально на стороне сервера, потому что при первом запуске сервера база данных инициализируется. К тому времени, когда пользователь действительно пытается войти, база данных уже инициализирована, и все в порядке. Однако это с треском проваливается, когда я пытаюсь создать интеграционный тест для этого. Когда я создаю класс, база данных еще не инициализирована, поэтому выполнение процедуры AttemptLogin завершается неудачно.

DataManager db = new DataManager();
// This fails miserably, because db hasn't initialized yet.
db.AttemptLogin("test", "test"); 

Хуже того, в коде используется среда Dart DI, поэтому я не имею прямого контроля над инициализацией класса DataManager. Это фактическая настройка класса:

setUp(() {
  app.addModule(new Module()
            ..bind(DataManager)
  app.setUp();
});

И затем это вызов для проверки функциональности входа в систему, который в конечном итоге вызывает функцию tryLogin, которая завершается ошибкой:

var req = new MockRequest("/user/login", contentType: 'JSON', method:'POST',
    body:JSON.encode(
      {"username" : 'test',
       "password" : 'test' }));

Как справиться с асинхронной природой инициализации базы данных и все еще проводить фиктивное тестирование? В частности, есть ли способ принудительно попытаться предпринять FutureLogin() Future для завершения инициализации класса DataManager?

Спасибо за вашу помощь, Грег

2 ответа

Решение

Как насчет использования решения @lrn s как

setUp(() {
  return DataManager.createNew().then((dm) {
    app.addModule(new Module()
            ..bind(DataManager, toValue: dm);
    app.setUp();
  }
});

Таким образом, вы уже проходите инициализированный DataManager экземпляр в DI. Если вы запросите это позже, вы всегда можете быть уверены, что оно уже инициализировано.

Если ваш класс имеет асинхронную настройку, вы не можете использовать обычный конструктор. В этом случае я бы просто использовал фабричный метод, возвращающий будущее:

class DataManager {
  final Db _db;
  DataManager._(this._db);
  static Future<DataManager> createNew() {
    var db = new Db("mongodb://127.0.0.1/test");
    return db.open().then((_) => new DataManager._(db));
  }
  ...
};

Я не знаю, как вы подключаете это к своей структуре внедрения зависимостей, но я думаю, что это может сделать что-то со статическими методами.

Другие вопросы по тегам