I have an abstract class DatabaseManager
, and an implementation DatabaseManagerImpl
, the latter is annotated like this:
@LazySingleton(as: DatabaseManager)
class DatabaseManagerImpl implements DatabaseManager {
A lot of other classes then depend on DatabaseManager
like this:
@LazySingleton()
class SomeClass {
const SomeClass(this._databaseManager);
final DatabaseManager _databaseManager;
I'm trying to add integration testing - as in, testing multiple modules at the same time, not the one where you run the app on a device. Basically, I'm testing how the backend executes certain features. Most of the backend classes depend on DatabaseManager
(it initializes and provides the database connection).
First of all, I want to initialize an in-memory database for testing and fill it with fake values, so I need to mock DatabaseManager
. The second reason is that I need to use sqflite_ffi
because the tests are run on Linux.
The problem is, I don't know where to put DatabaseManagerMock
: under the lib or test folder?
test
folder (which is where it belongs ideally), I can't generate injectable config for it because it (obviously) doesn't get included into the generated file under lib
. I had an idea to generate a second injectable config file for tests and then run them in this order:await configureDependencies() // from the main project
await configureTestDependencies() // from tests
But injectable breaks when I do that: it can't generate proper import paths for the test directory.
DatabaseManagerMock
under the lib folder. Since I need sqflite_ffi
only for testing, it should be a dev dependency, but that gives a depend_on_referenced_packages warning when I import it to use in DatabaseManagerMock
.What is the proper way to do this? I think I might be overthinking and there is a completely different approach to this that I'm missing.
I fixed the problem with the generated imports for injectable and the PR was merged yesterday, so now it's possible to do this:
Create a second injectable initializer under the test
directory:
// test/injectable/configure_test_dependencies.dart
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';
import 'configure_test_dependencies.config.dart';
const testEnv = 'test';
final getIt = GetIt.instance;
@InjectableInit(
initializerName: 'testInit',
preferRelativeImports: true,
generateForDir: ['test', 'lib'],
)
Future<GetIt> configureTestDependencies() {
return getIt.testInit(environment: testEnv);
}
Then create the mock classes under test/
and set their environment to testEnv
. Their corresponding non-mock classes (in lib/
) must be within some other environment, like mainEnv
. This is not important for the classes that are not mocked. Example:
// test/mocks/database_manager_mock.dart
@LazySingleton(as: DatabaseManager, env: [testEnv])
class DatabaseManagerMock extends DatabaseManager {
Then configureTestDependencies()
generates get_it initializer that includes all the annotated classes from lib/
plus the new mock classes.