问题
Futures in Dart are the bane of my existence.
I have a class, which calls an async (Future) function to start up the database instance like so:
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
}
}
This works OK server-side because when the server first starts up, the database is initialized. By the time a user actually attempts to log in, the database has been initialized and all is well. However, this fails miserably when I try to create an integration test for this. When I create the class, the database isn't yet initialized, so running the AttemptLogin routine fails.
DataManager db = new DataManager();
// This fails miserably, because db hasn't initialized yet.
db.AttemptLogin("test", "test");
Worse, the code uses the Dart DI framework, so I don't actually have direct control over the initialization of the DataManager class. This is the actual setup of the class:
setUp(() {
app.addModule(new Module()
..bind(DataManager)
app.setUp();
});
And then this is the call to test the login functionality, which ultimately calls the attemptLogin function which fails:
var req = new MockRequest("/user/login", contentType: 'JSON', method:'POST',
body:JSON.encode(
{"username" : 'test',
"password" : 'test' }));
How does one deal with the async nature of the the database init and still do mock testing? Specifically, is there a way to force the attemptLogin() Future to somehow wait for the completion of the DataManager class initialization?
Thanks for your help, Greg
回答1:
what about using @lrn s solution like
setUp(() {
return DataManager.createNew().then((dm) {
app.addModule(new Module()
..bind(DataManager, toValue: dm);
app.setUp();
}
});
This way you already pass an initialized DataManager
instance into the DI. If you request it later on you always can be sure it is already initialized.
回答2:
If your class has asynchronous setup, you can't use a normal constructor. In that case, I'd just use a factory method returning a future:
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));
}
...
};
I don't know how you hook that into your dependency injection framework, but I guess it can do something with static methods.
来源:https://stackoverflow.com/questions/24592070/waiting-for-my-class-to-initialize-or-how-to-wait-for-a-future-to-complete