2

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?

  1. if I put it under the 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.

  1. Putting 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.

splaytreez
  • 552
  • 5
  • 13

1 Answers1

0

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.

splaytreez
  • 552
  • 5
  • 13