in script/tool/lib/src/native_test_command.dart [198:334]
Future<_PlatformResult> _testAndroid(
RepositoryPackage plugin, _TestMode mode) async {
bool exampleHasUnitTests(RepositoryPackage example) {
return example.directory
.childDirectory('android')
.childDirectory('app')
.childDirectory('src')
.childDirectory('test')
.existsSync() ||
example.directory.parent
.childDirectory('android')
.childDirectory('src')
.childDirectory('test')
.existsSync();
}
bool exampleHasNativeIntegrationTests(RepositoryPackage example) {
final Directory integrationTestDirectory = example.directory
.childDirectory('android')
.childDirectory('app')
.childDirectory('src')
.childDirectory('androidTest');
// There are two types of integration tests that can be in the androidTest
// directory:
// - FlutterTestRunner.class tests, which bridge to Dart integration tests
// - Purely native tests
// Only the latter is supported by this command; the former will hang if
// run here because they will wait for a Dart call that will never come.
//
// This repository uses a convention of putting the former in a
// *ActivityTest.java file, so ignore that file when checking for tests.
// Also ignore DartIntegrationTest.java, which defines the annotation used
// below for filtering the former out when running tests.
//
// If those are the only files, then there are no tests to run here.
return integrationTestDirectory.existsSync() &&
integrationTestDirectory
.listSync(recursive: true)
.whereType<File>()
.any((File file) {
final String basename = file.basename;
return !basename.endsWith('ActivityTest.java') &&
basename != 'DartIntegrationTest.java';
});
}
final Iterable<RepositoryPackage> examples = plugin.getExamples();
bool ranUnitTests = false;
bool ranAnyTests = false;
bool failed = false;
bool hasMissingBuild = false;
for (final RepositoryPackage example in examples) {
final bool hasUnitTests = exampleHasUnitTests(example);
final bool hasIntegrationTests =
exampleHasNativeIntegrationTests(example);
if (mode.unit && !hasUnitTests) {
_printNoExampleTestsMessage(example, 'Android unit');
}
if (mode.integration && !hasIntegrationTests) {
_printNoExampleTestsMessage(example, 'Android integration');
}
final bool runUnitTests = mode.unit && hasUnitTests;
final bool runIntegrationTests = mode.integration && hasIntegrationTests;
if (!runUnitTests && !runIntegrationTests) {
continue;
}
final String exampleName = example.displayName;
_printRunningExampleTestsMessage(example, 'Android');
final GradleProject project = GradleProject(
example.directory,
processRunner: processRunner,
platform: platform,
);
if (!project.isConfigured()) {
printError('ERROR: Run "flutter build apk" on $exampleName, or run '
'this tool\'s "build-examples --apk" command, '
'before executing tests.');
failed = true;
hasMissingBuild = true;
continue;
}
if (runUnitTests) {
print('Running unit tests...');
final int exitCode = await project.runCommand('testDebugUnitTest');
if (exitCode != 0) {
printError('$exampleName unit tests failed.');
failed = true;
}
ranUnitTests = true;
ranAnyTests = true;
}
if (runIntegrationTests) {
// FlutterTestRunner-based tests will hang forever if run in a normal
// app build, since they wait for a Dart call from integration_test that
// will never come. Those tests have an extra annotation to allow
// filtering them out.
const String filter =
'notAnnotation=io.flutter.plugins.DartIntegrationTest';
print('Running integration tests...');
final int exitCode = await project.runCommand(
'app:connectedAndroidTest',
arguments: <String>[
'-Pandroid.testInstrumentationRunnerArguments.$filter',
],
);
if (exitCode != 0) {
printError('$exampleName integration tests failed.');
failed = true;
}
ranAnyTests = true;
}
}
if (failed) {
return _PlatformResult(RunState.failed,
error: hasMissingBuild
? 'Examples must be built before testing.'
: null);
}
if (!mode.integrationOnly && !ranUnitTests) {
printError('No unit tests ran. Plugins are required to have unit tests.');
return _PlatformResult(RunState.failed,
error: 'No unit tests ran (use --exclude if this is intentional).');
}
if (!ranAnyTests) {
return _PlatformResult(RunState.skipped);
}
return _PlatformResult(RunState.succeeded);
}