Currently we're automatically registering plugins both when the FlutterEngine is constructed and in the `flutter create` template, when FlutterActivity#configureFlutterEngine is called. The initial registration is too early to contain a reference to the activity and the second registration can cause problems in some plugins. This alters the flow so automatic registration happens in two discrete places, and contains the `activity` in its first and only call for most apps. 1. We're no longer automatically registering plugins on `FlutterEngine` in any of our activities/fragments at construction time. But since the FlutterEngine default constructor still automatically registers plugins, anyone constructing the engine themselves (for example, in a service) is still going to get automatic registration at `FlutterEngine` instantiation time. 2. We now automatically register plugins in the base `FlutterActivity`'s `configureFlutterEngine` hook. Anyone using `FlutterActivity` (or `FlutterFragment`) should be automatically registered once that hook is called. Right now the `flutter create` template overrides the base class method with a subclass that registers everything manually in the same spot. But with this in place we can safely recommend to remove the subclass and rely on this hook to automatically register going forward. Registering at this time means `activity` is set correctly.
Unit testing Java code
All Java code in the engine should now be able to be tested with Robolectric 3.8 and JUnit 4. The test suite has been added after the bulk of the Java code was first written, so most of these classes do not have existing tests. Ideally code after this point should be tested, either with unit tests here or with integration tests in other repos.
Adding a new test
- Create a file under
test/matching the path and name of the class under test. For example,shell/platform/android/io/flutter/util/Preconditions.java->shell/platform/android/**test**/io/flutter/util/Preconditions**Test**.java. - Add your file to the
sourcesof therobolectric_testsbuild target in/shell/platform/android/BUILD.gn. This compiles the test class into the test jar. - Add your class to the
@SuiteClassesannotation inFlutterTestSuite.java. This makes sure the test is actually executed at run time. - Write your test.
- Build and run with
testing/run_tests.py [--type=java] [--java-filter=<test_class_name>].
Q&A
Why are we using Robolectric 3.8 when Robolectric 4+ is current?
Robolectric 4+ uses the AndroidX libraries, and the engine sources use the
deprecated android.support ones. See
flutter/flutter#23586. If
this is an issue we could use Jetifier on flutter.jar first and then run
the tests, but it would add an extra point of failure.
My new test won't run. There's a "ClassNotFoundException".
Your test is probably using a dependency that we haven't needed yet. You
probably need to find the dependency you need, add it to the
flutter/android/robolectric_bundle CIPD package, and then re-run gclient sync. See "Updating a CIPD dependency" below.
My new test won't compile. It can't find one of my imports.
You could be using a brand new dependency. If so, you'll need to add it to the CIPD package for the robolectric tests. See "Updating a CIPD dependency" below.
Then you'll also need to add the jar to the robolectric_tests build target.
Add //third_party/robolectric/lib/<dependency.jar> to
robolectric_tests._jar_dependencies in /shell/platform/android/BUILD.gn.
There's also a chance that you're using a dependency that we're relying on at
runtime, but not compile time. If so you'll just need to update
_jar_dependencies in BUILD.gn.
Updating a CIPD dependency
See the Chromium instructions on "Updating a CIPD
dependency"
for how to upload a package update to CIPD. Download and extract the latest
package from CIPD and then copy
shell/platform/android/test/cipd.yaml into the extracted directory
to use as the base for the pre-existing package. Add new dependencies to lib/.
Once you've uploaded the new version, also make sure to tag it with the updated timestamp and robolectric version (most likely still 3.8, unless you've migrated all the packages to 4+).
$ cipd set-tag flutter/android/robolectric_bundle --version=<new_version_hash> -tag=last_updated:<timestamp>
Example of a last-updated timestamp: 2019-07-29T15:27:42-0700
You can generate the same date format with date +%Y-%m-%dT%T%z.
$ cipd set-tag flutter/android/robolectric_bundle --version=<new_version_hash> -tag=robolectric_version:<robolectric_version>
You can run cipd describe flutter/android/robolectric_bundle --version=<new_version_hash> to verify. You should see:
Package: flutter/android/robolectric_bundle
Instance ID: <new_version_hash>
...
Tags:
last_updated:<timestamp>
robolectric_version:<robolectric_version>
Then update the DEPS file (located at /src/flutter/DEPS) to use the new version by pointing to
your new last_updated_at tag.
'src/third_party/robolectric': {
'packages': [
{
'package': 'flutter/android/robolectric_bundle',
'version': 'last_updated:<timestamp>'
}
],
'condition': 'download_android_deps',
'dep_type': 'cipd',
},
You can now re-run gclient sync to fetch the latest package version.