diff --git a/script/tool/lib/src/common/gradle.dart b/script/tool/lib/src/common/gradle.dart index 746536075014..8dea4836f170 100644 --- a/script/tool/lib/src/common/gradle.dart +++ b/script/tool/lib/src/common/gradle.dart @@ -44,12 +44,13 @@ class GradleProject { /// Runs a `gradlew` command with the given parameters. Future runCommand( - String target, { + String task, { + List additionalTasks = const [], List arguments = const [], }) { return processRunner.runAndStream( gradleWrapper.path, - [target, ...arguments], + [task, ...additionalTasks, ...arguments], workingDir: androidDirectory, ); } diff --git a/script/tool/lib/src/native_test_command.dart b/script/tool/lib/src/native_test_command.dart index f9967ca0523e..f6eb3c164e24 100644 --- a/script/tool/lib/src/native_test_command.dart +++ b/script/tool/lib/src/native_test_command.dart @@ -268,6 +268,7 @@ this command. } final Iterable examples = plugin.getExamples(); + final String pluginName = plugin.directory.basename; bool ranUnitTests = false; bool ranAnyTests = false; @@ -317,7 +318,15 @@ this command. if (runUnitTests) { print('Running unit tests...'); - final int exitCode = await project.runCommand('testDebugUnitTest'); + const String taskName = 'testDebugUnitTest'; + // Target the unit tests in the app and plugin specifically, to avoid + // transitively running tests in dependencies. If unit tests have + // already run in an earlier example, only run any app-level unit tests. + final List pluginTestTask = [ + if (!ranUnitTests) '$pluginName:$taskName' + ]; + final int exitCode = await project.runCommand('app:$taskName', + additionalTasks: pluginTestTask); if (exitCode != 0) { printError('$exampleName unit tests failed.'); failed = true; diff --git a/script/tool/test/native_test_command_test.dart b/script/tool/test/native_test_command_test.dart index 3d327a0e3959..b4e06b9b7e38 100644 --- a/script/tool/test/native_test_command_test.dart +++ b/script/tool/test/native_test_command_test.dart @@ -438,7 +438,10 @@ void main() { orderedEquals([ ProcessCall( androidFolder.childFile('gradlew').path, - const ['testDebugUnitTest'], + const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], androidFolder.path, ), ]), @@ -470,13 +473,62 @@ void main() { orderedEquals([ ProcessCall( androidFolder.childFile('gradlew').path, - const ['testDebugUnitTest'], + const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], androidFolder.path, ), ]), ); }); + test('only runs plugin-level unit tests once', () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline) + }, + examples: ['example1', 'example2'], + extraFiles: [ + 'example/example1/android/gradlew', + 'example/example1/android/app/src/test/example_test.java', + 'example/example2/android/gradlew', + 'example/example2/android/app/src/test/example_test.java', + ], + ); + + await runCapturingPrint(runner, ['native-test', '--android']); + + final List examples = plugin.getExamples().toList(); + final Directory androidFolder1 = + examples[0].platformDirectory(FlutterPlatform.android); + final Directory androidFolder2 = + examples[1].platformDirectory(FlutterPlatform.android); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + androidFolder1.childFile('gradlew').path, + const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], + androidFolder1.path, + ), + ProcessCall( + androidFolder2.childFile('gradlew').path, + const [ + 'app:testDebugUnitTest', + ], + androidFolder2.path, + ), + ]), + ); + }); + test('runs Java integration tests', () async { final RepositoryPackage plugin = createFakePlugin( 'plugin', @@ -629,7 +681,10 @@ public class FlutterActivityTest { orderedEquals([ ProcessCall( androidFolder.childFile('gradlew').path, - const ['testDebugUnitTest'], + const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], androidFolder.path, ), ProcessCall( @@ -708,7 +763,10 @@ public class FlutterActivityTest { orderedEquals([ ProcessCall( androidFolder.childFile('gradlew').path, - const ['testDebugUnitTest'], + const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], androidFolder.path, ), ]), @@ -854,7 +912,7 @@ public class FlutterActivityTest { processRunner.mockProcessesForExecutable[gradlewPath] = [ FakeProcessInfo( - MockProcess(), ['testDebugUnitTest']), // unit passes + MockProcess(), ['app:testDebugUnitTest']), // unit passes FakeProcessInfo(MockProcess(exitCode: 1), ['app:connectedAndroidTest']), // integration fails ]; @@ -1395,8 +1453,13 @@ public class FlutterActivityTest { expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall(androidFolder.childFile('gradlew').path, - const ['testDebugUnitTest'], androidFolder.path), + ProcessCall( + androidFolder.childFile('gradlew').path, + const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], + androidFolder.path), getTargetCheckCall(pluginExampleDirectory, 'ios'), getRunTestCall(pluginExampleDirectory, 'ios', destination: 'foo_destination'),