Closed mrverdant13 closed 2 years ago
Actually, I just noticed that onSnapshot
is an extension method. Thus, it cannot be stubbed. 😔
Yes testing streams is not always convenient. I'm not an expert in using expectLater, emitsInOrder but the rxdart package has some good examples.
Regarding mocking, well, the purpose of inMemory database factory is to provide a testable context (i.e. you can use it to mock whatever you want since you can simply write to the database to add test data. Indeed onSnapshot are extensions, basically record and store refs are just definitions, but these extensions ends up calling sembast and the whole abstraction is around the factory concept (sorry I come from the java world). Maybe it is a bad choice (and code completion is not always as good for extension than for methods).
Here is a simple onSnapshot test:
import 'package:sembast/sembast.dart';
import 'package:sembast/sembast_memory.dart';
import 'package:test/test.dart';
void main() {
// This is needed for flutter tests
disableSembastCooperator();
// Using in memory factory
var factory = databaseFactoryMemory;
test('onSnapshot', () async {
late Database db;
// Key is an int, value is an int
var store = StoreRef<int, int>.main();
// Key is 1
var record = store.record(1);
// onSnapshot values
Stream<int?> watchValue() async* {
yield* record.onSnapshot(db).map((record) => record?.value);
}
// Create a blank in memory database
db = await factory.openDatabase(sembastInMemoryDatabasePath);
// Test stream, expect value null, 1, 2, null (not existing, value 1 created, value 2 updated, deleted);
var future = watchValue().take(4).toList();
// add
await record.put(db, 1);
// update
await record.put(db, 2);
// delete
await record.delete(db);
// Test stream result.
expect(await future, [null, 1, 2, null]);
await db.close();
});
}
Sometimes I also manually listen and cancel subscription for finer testing. This repository has some tests (https://github.com/tekartik/sembast.dart/blob/master/sembast_test/lib/listener_test.dart). Some tests are very old (I think even some were made before await
was available) but I still maintain them.
However I would be happy if someone has a better ways to test this.
Fair enough. Thanks for the detailed answer!
I ended up listening to the records on my tests and I worked like a charm. As you said, it is more suitable for more controlled testing.
PS: The in-memory DB would be considered a fake instead of a mock. Thanks again for the awesome package! 🤜🏼✨🤛🏼
What is the best way to test
RecordRef.onSnapshot
?On regular
Future
-based methods, the info provided in the docs is more than enough for tests.Nevertheless, for
Stream
-based methods, this is not the case.Let's say we have a watcher method as follows:
I wonder what is the best approach to test a method like this one.
So far, I only think of mocking the
StoreRef
that returns a mockrecord
and, at the same time, thisrecord
has a stubbedonSnapshot
method to return a fakeStream
of values. However, this is cumbersome, so I wanted to ask for advice here.Thanks for the awesome package!