.context/docs/testing-methodology.md
Paths:
test/**/*.dart, excluding tests tagged sdk, network, git, integration, or migration.test/testing_helpers/ fixtures and fakes.Run:
dart test -x "sdk || network || git || integration || migration"
Use:
TestFactory.fastContext()TestFactory.fastCommandRunner()FakeFlutterServiceFakeFlutterReleaseClientFakeGitServiceFakeFlutterSdkFixtureThis layer proves command/workflow logic, parsing, local file effects, cache bookkeeping, fake SDK setup states, and happy-path plumbing in seconds. It does not prove real Git clones, real Flutter SDK setup, live network behavior, recovery from real corrupt caches, or concurrency against real installed SDKs.
Paths and commands:
fvm integration-testdart run grinder integration-testtest/integration/integration-test and migration-testThis layer proves real clone/install/setup/recovery/global-link behavior. It is slow and can mutate the real FVM cache, so local runs require deliberate intent.
Run the live release-schema drift guard on demand:
dart test -t network
The guard checks that production release parsing still accepts live Flutter release metadata and that current channel releases still carry modern SDK metadata not represented in the minimal fixture.
Prefer the fast factory for ordinary command and workflow tests:
final runner = TestFactory.fastCommandRunner();
final exitCode = await runner.run(['fvm', 'install', '3.10.0']);
expect(exitCode, ExitCode.success.code);
Use a fast context when you need direct service access:
final context = TestFactory.fastContext();
final flutter = context.get<FlutterService>() as FakeFlutterService;
The fast factory wires:
FlutterService to FakeFlutterServiceFlutterReleaseClient to FakeFlutterReleaseClientGitService to FakeGitServiceUse TestFactory.context() only when you need the default lower-level test context or custom generators.
FakeFlutterSdkFixture.install() writes fixture-backed SDK layouts under the isolated test cache.
States:
installedNotSetup: root version file and executables only.installedSetup: version metadata plus Dart SDK cache files.versionMismatch: legacy version and JSON metadata intentionally disagree.invalidExecutable: SDK layout without the Flutter executable.Example:
FakeFlutterSdkFixture.install(
context,
FlutterVersion.parse('3.10.0'),
state: FakeFlutterSdkState.installedSetup,
);
Fixture resolution intentionally keeps a fallback for versions without dedicated root fixtures. Tests still install versions such as 2.0.0, 3.0.0, and commit refs through that fallback.
The fast release client reads test/fixtures/releases/minimal_releases.json. Fake install validation derives allowed release versions from that fixture, so the fixture is the single source of truth.
When the production release schema changes:
dart test -t network.minimal_releases.json only if the fast layer needs the new schema.Use the fixture recorder when a fake SDK layout needs new root metadata:
dart test test/testing_helpers/record_test_fixtures_test.dart
The recorder workflow should preserve:
versionbin/cache/flutter.version.jsonDo:
workingDirectoryOverride instead of mutating Directory.current.FvmContext.appConfigPath.Do not:
LocalAppConfig from fast tests.void main() {
late TestCommandRunner runner;
setUp(() {
runner = TestFactory.fastCommandRunner();
});
test('installs a fixture-backed release', () async {
final exitCode = await runner.run(['fvm', 'install', '3.10.0']);
expect(exitCode, ExitCode.success.code);
final cacheService = runner.context.get<CacheService>();
final version = FlutterVersion.parse('3.10.0');
expect(cacheService.getVersion(version), isNotNull);
});
}
Use TestLogger for prompts:
final context = TestFactory.fastContext(
generators: {
Logger: (context) => TestLogger(context)
..setConfirmResponse('Would you like to continue?', true),
},
);
final runner = TestFactory.fastCommandRunner(context: context);
Use tags to keep the fast layer clean:
network: live HTTP or release metadata.git: real Git behavior.sdk: real or local Flutter SDK behavior.integration: broad real integration workflows.migration: v3-to-v4 migration coverage.The default fast command excludes all of those tags.
Before pushing:
dart analyze --fatal-infos
dcm analyze lib
dart test -x "sdk || network || git || integration || migration"
For release-schema drift:
dart test -t network
For real integration proof, prefer CI unless you explicitly accept the local cache impact:
dart run grinder integration-test