Pārlūkot izejas kodu

Unit tests for flutter and android (#558)

* added initial test support

* added travis setup

* modified tests

* test new travis script

* added tests for android

* added android unit test support

* upgraded script

* fixed typo

* added execute permissions

* configured gradle

* configured github actions

* updated github actions

* added andorid ut

* added android yml

* renamed files and tasks

* removed redundant name

* renamed tasks

* fixed andorid ut script
Rafal Wachol 6 gadi atpakaļ
vecāks
revīzija
4ecf456269

+ 20 - 0
.github/workflows/android_ut.yml

@@ -0,0 +1,20 @@
+name: Android Unit Tests
+
+on: [push]
+
+jobs:
+  test:
+    name: Linux Android Unit Tests
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v1
+      - uses: actions/setup-java@v1
+        with:
+          java-version: '12.x'
+      - uses: subosito/flutter-action@v1
+        with:
+          flutter-version: '1.7.8+hotfix.4'
+      - run: flutter doctor
+      - run: flutter pub get
+      - run: sh android_test.sh 

+ 20 - 0
.github/workflows/flutter_ut.yml

@@ -0,0 +1,20 @@
+name: Flutter Unit Tests
+
+on: [push]
+
+jobs:
+  test:
+    name: Linux Flutter Unit Tests
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v1
+      - uses: actions/setup-java@v1
+        with:
+          java-version: '12.x'
+      - uses: subosito/flutter-action@v1
+        with:
+          flutter-version: '1.7.8+hotfix.4'
+      - run: flutter doctor
+      - run: flutter pub get
+      - run: flutter test

+ 4 - 1
.gitignore

@@ -4,6 +4,7 @@
 .vscode
 .packages
 .pub/
+.gradle/
 build/
 ios/.generated/
 packages
@@ -14,4 +15,6 @@ example/ios/Podfile.lock
 **/Flutter/Flutter.framework/
 **/Flutter/Generated.xcconfig/
 **/Flutter/flutter_assets/
-flutter_export_environment.sh
+example/ios/Flutter/flutter_export_environment.sh
+android/.project
+android/.settings/

+ 0 - 12
android/.gitignore

@@ -1,12 +0,0 @@
-*.iml
-.gradle
-/local.properties
-/.idea/workspace.xml
-/.idea/libraries
-.DS_Store
-/build
-/captures
-
-/gradle
-/gradlew
-/gradlew.bat

+ 16 - 0
android/android.iml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.system.id="GRADLE" type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="android-gradle" name="Android-Gradle">
+      <configuration>
+        <option name="GRADLE_PROJECT_PATH" value=":" />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 21 - 1
android/build.gradle

@@ -45,7 +45,27 @@ android {
     lintOptions {
         disable 'InvalidPackage'
     }
+
+    testOptions {
+        unitTests {
+            includeAndroidResources = true
+        }
+    }
 }
 dependencies {
-    implementation group: 'androidx.appcompat', name: 'appcompat', version: '1.0.0'
+    implementation 'androidx.appcompat:appcompat:1.0.2'
+
+	testImplementation 'junit:junit:4.12'
+    testImplementation 'androidx.test:core:1.2.0'
+
+//    When running unit tests for project, gradle needs to have flutter.jar in path
+//    since there's no FLUTTER_HOME variable, we need to pass flutterPath from console with command:
+//    ./gradlew test -DflutterPath=/Users/rafal.wachol/Utils/flutter
+//
+//    while develop you can set path to this jar explicitly so IDE won't complain
+    if(System.getProperty('flutterPath')) {
+        testImplementation files(System.getProperty('flutterPath') + '/bin/cache/artifacts/engine/android-x64/flutter.jar')
+    }
+
+    testImplementation 'org.mockito:mockito-inline:2.28.2'
 }

+ 169 - 0
android/flutter_webview_plugin.iml

@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id=":flutter_webview_plugin" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/../example/android" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="android-gradle" name="Android-Gradle">
+      <configuration>
+        <option name="GRADLE_PROJECT_PATH" value=":flutter_webview_plugin" />
+      </configuration>
+    </facet>
+    <facet type="android" name="Android">
+      <configuration>
+        <option name="SELECTED_BUILD_VARIANT" value="debug" />
+        <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
+        <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
+        <afterSyncTasks>
+          <task>generateDebugSources</task>
+        </afterSyncTasks>
+        <option name="ALLOW_USER_CONFIGURATION" value="false" />
+        <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
+        <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
+        <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/res/rs/debug;file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/res/resValues/debug" />
+        <option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/res/rs/androidTest/debug" />
+        <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
+        <option name="PROJECT_TYPE" value="1" />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
+    <output url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
+    <output-test url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
+    </content>
+    <content url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin">
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/source/apt/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/aidl_source_output_dir/debug/compileDebugAidl/out" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/renderscript_source_output_dir/debug/compileDebugRenderscript/out" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/res/rs/debug" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/res/resValues/debug" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/aidl_source_output_dir/debugAndroidTest/compileDebugAndroidTestAidl/out" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/renderscript_source_output_dir/debugAndroidTest/compileDebugAndroidTestRenderscript/out" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/res/rs/androidTest/debug" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/res/resValues/androidTest/debug" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/source/apt/test/debug" isTestSource="true" generated="true" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/not_namespaced_r_class_sources" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/generated/source/r" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/aapt_friendly_merged_manifests" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/annotation_processor_list" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/annotations_typedef_file" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/annotations_zip" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/blame" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/check_manifest_result" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/compile_only_not_namespaced_r_class_jar" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/consumer_proguard_file" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/incremental" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/intermediate-jars" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/javac" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/jniLibs" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/library_and_local_jars_jni" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/library_assets" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/library_manifest" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/lint_jar" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/merged_assets" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/merged_manifests" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/packaged-classes" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/packaged_res" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/public_res" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/res" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/rs" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/shader_assets" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/shaders" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/sourceFolderJavaResources" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/symbols" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/tmp" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/transforms" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/intermediates/unit_test_config_directory" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/outputs" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/reports" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/test-results" />
+      <excludeFolder url="file://$MODULE_DIR$/../example/build/flutter_webview_plugin/tmp" />
+    </content>
+    <orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Gradle: androidx.swiperefreshlayout:swiperefreshlayout:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-ui:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.viewpager:viewpager:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.objenesis:objenesis:2.6@jar" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: androidx.test:core:1.2.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.drawerlayout:drawerlayout:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.documentfile:documentfile:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.localbroadcastmanager:localbroadcastmanager:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.appcompat:appcompat:1.0.2@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: __local_aars__:/Users/rafal.wachol/Utils/flutter/bin/cache/artifacts/engine/android-arm/flutter.jar:unspecified@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.cursoradapter:cursoradapter:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.customview:customview:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable-animated:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.asynclayoutinflater:asynclayoutinflater:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable:1.0.1@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.interpolator:interpolator:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.0.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-utils:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.print:print:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.slidingpanelayout:slidingpanelayout:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.arch.core:core-common:2.0.0@jar" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12@jar" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.annotation:annotation:1.0.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.coordinatorlayout:coordinatorlayout:1.0.0@aar" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: androidx.test:monitor:1.2.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.core:core:1.0.1@aar" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.mockito:mockito-inline:2.28.2@jar" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: net.bytebuddy:byte-buddy-agent:1.9.10@jar" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.mockito:mockito-core:2.28.2@jar" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: net.bytebuddy:byte-buddy:1.9.10@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.collection:collection:1.0.0@jar" level="project" />
+  </component>
+</module>

+ 8 - 0
android/local.properties

@@ -0,0 +1,8 @@
+## This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+#Mon Jun 03 19:01:20 BST 2019
+sdk.dir=C\:\\Users\\Gloria\\AppData\\Local\\Android\\Sdk

+ 3 - 3
android/src/main/java/com/flutter_webview_plugin/FlutterWebviewPlugin.java

@@ -38,7 +38,7 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
         channel.setMethodCallHandler(instance);
     }
 
-    private FlutterWebviewPlugin(Activity activity, Context context) {
+    FlutterWebviewPlugin(Activity activity, Context context) {
         this.activity = activity;
         this.context = context;
     }
@@ -88,7 +88,7 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
         }
     }
 
-    private void openUrl(MethodCall call, MethodChannel.Result result) {
+     void openUrl(MethodCall call, MethodChannel.Result result) {
         boolean hidden = call.argument("hidden");
         String url = call.argument("url");
         String userAgent = call.argument("userAgent");
@@ -172,7 +172,7 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
         result.success(null);
     }
 
-    private void close(MethodCall call, MethodChannel.Result result) {
+    void close(MethodCall call, MethodChannel.Result result) {
         if (webViewManager != null) {
             webViewManager.close(call, result);
             webViewManager = null;

+ 41 - 0
android/src/test/java/com/flutter_webview_plugin/FlutterWebviewPluginTest.java

@@ -0,0 +1,41 @@
+package com.flutter_webview_plugin;
+
+import android.app.Activity;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+import io.flutter.plugin.common.ErrorLogResult;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+
+import static org.mockito.Mockito.verify;
+
+public class FlutterWebviewPluginTest {
+
+    @Mock
+    Activity mockActivity;
+
+    MethodCall mockMethodCall;
+    MethodChannel.Result mockResult;
+
+    @Spy
+    FlutterWebviewPlugin flutterWebviewPlugin = new FlutterWebviewPlugin(mockActivity, mockActivity);
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void shouldInvokeClose() {
+        mockMethodCall = new MethodCall("close", null);
+        mockResult = new ErrorLogResult("");
+        flutterWebviewPlugin.onMethodCall(mockMethodCall, mockResult);
+        verify(flutterWebviewPlugin).close(mockMethodCall, mockResult);
+
+    }
+}

+ 1 - 0
android/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker

@@ -0,0 +1 @@
+mock-maker-inline

+ 3 - 0
android_test.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+cd example/android
+./gradlew test -DflutterPath=$FLUTTER_HOME

+ 2 - 3
example/android/.gitignore

@@ -8,6 +8,5 @@
 /captures
 PluginRegistry.java
 
-/gradle
-/gradlew
-/gradlew.bat
+.project
+.settings

+ 4 - 2
example/android/app/build.gradle

@@ -42,7 +42,9 @@ flutter {
 }
 
 dependencies {
+    testImplementation 'junit:junit:4.12'
+
     androidTestImplementation 'androidx.annotation:annotation:1.0.2'
-    androidTestImplementation 'androidx.test:runner:1.1.1'
-    androidTestImplementation 'androidx.test:rules:1.1.1'
+    androidTestImplementation 'androidx.test:runner:1.2.0'
+    androidTestImplementation 'androidx.test:rules:1.2.0'
 }

BIN
example/android/gradle/wrapper/gradle-wrapper.jar


+ 6 - 0
example/android/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,6 @@
+#Fri Jun 23 08:50:38 CEST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

+ 160 - 0
example/android/gradlew

@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

+ 90 - 0
example/android/gradlew.bat

@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

+ 10 - 3
lib/src/base.dart

@@ -16,15 +16,22 @@ enum WebViewState { shouldStart, startLoad, finishLoad, abortLoad }
 
 /// Singleton class that communicate with a Webview Instance
 class FlutterWebviewPlugin {
-  factory FlutterWebviewPlugin() => _instance ??= FlutterWebviewPlugin._();
+  factory FlutterWebviewPlugin() {
+    if(_instance == null) {
+      const MethodChannel methodChannel = const MethodChannel(_kChannel);
+      _instance = FlutterWebviewPlugin.private(methodChannel);
+    }
+    return _instance;
+  }
 
-  FlutterWebviewPlugin._() {
+  @visibleForTesting
+  FlutterWebviewPlugin.private(this._channel) {
     _channel.setMethodCallHandler(_handleMessages);
   }
 
   static FlutterWebviewPlugin _instance;
 
-  final _channel = const MethodChannel(_kChannel);
+  final MethodChannel _channel;
 
   final _onBack = StreamController<Null>.broadcast();
   final _onDestroy = StreamController<Null>.broadcast();

+ 5 - 0
pubspec.yaml

@@ -21,3 +21,8 @@ flutter:
 dependencies:
   flutter:
     sdk: flutter
+
+dev_dependencies:
+  mockito: ^4.1.0
+  flutter_test:
+    sdk: flutter

+ 26 - 0
scripts/before_build_apks.sh

@@ -0,0 +1,26 @@
+#!/bin/bash
+wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
+mkdir android-sdk
+unzip -qq sdk-tools-linux-3859397.zip -d android-sdk
+export ANDROID_HOME=`pwd`/android-sdk
+export PATH=`pwd`/android-sdk/tools/bin:$PATH
+mkdir -p /home/travis/.android # silence sdkmanager warning
+echo 'count=0' > /home/travis/.android/repositories.cfg # silence sdkmanager warning
+        # suppressing output of sdkmanager to keep log under 4MB (travis limit)
+echo y | sdkmanager "tools" >/dev/null
+echo y | sdkmanager "platform-tools" >/dev/null
+echo y | sdkmanager "build-tools;28.0.3" >/dev/null
+echo y | sdkmanager "platforms;android-28" >/dev/null
+echo y | sdkmanager "extras;android;m2repository" >/dev/null
+echo y | sdkmanager "extras;google;m2repository" >/dev/null
+echo y | sdkmanager "patcher;v4" >/dev/null
+sdkmanager --list
+wget https://services.gradle.org/distributions/gradle-4.10.2-all.zip
+unzip -qq gradle-4.10.2-all.zip
+export GRADLE_HOME=$PWD/gradle-4.10.2
+export PATH=$GRADLE_HOME/bin:$PATH
+gradle -v
+git clone --depth=1 https://github.com/flutter/flutter.git
+export PATH=`pwd`/flutter/bin:`pwd`/flutter/bin/cache/dart-sdk/bin:$PATH
+flutter doctor
+pub global activate flutter_plugin_tools

+ 44 - 0
test/flutter_webview_plugin_test.dart

@@ -0,0 +1,44 @@
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
+import 'package:mockito/mockito.dart';
+
+void main() {
+  MockMethodChannel methodChannel;
+  FlutterWebviewPlugin webview;
+
+  setUp(() {
+    methodChannel = MockMethodChannel();
+    webview = new FlutterWebviewPlugin.private(methodChannel);
+  });
+
+
+  group('Method channel invoke', () {
+    test('Should invoke close', () async {
+      webview.close();
+      verify(methodChannel.invokeMethod('close')).called(1);
+    });
+    test('Should invoke reload', () async {
+      webview.reload();
+      verify(methodChannel.invokeMethod('reload')).called(1);
+    });
+    test('Should invoke goBack', () async {
+      webview.goBack();
+      verify(methodChannel.invokeMethod('back')).called(1);
+    });
+    test('Should invoke goForward', () async {
+      webview.goForward();
+      verify(methodChannel.invokeMethod('forward')).called(1);
+    });
+    test('Should invoke hide', () async {
+      webview.hide();
+      verify(methodChannel.invokeMethod('hide')).called(1);
+    });
+    test('Should invoke show', () async {
+      webview.show();
+      verify(methodChannel.invokeMethod('show')).called(1);
+    });
+  });
+}
+
+class MockMethodChannel extends Mock implements MethodChannel {}

+ 96 - 0
travis.yml.bak

@@ -0,0 +1,96 @@
+matrix:
+  include:
+    # # Job 1) Run analyzer
+    # - os: linux
+    #   env:
+    #     - SHARD=Analyze
+    #   sudo: false
+    #   addons:
+    #     apt:
+    #       # Flutter depends on /usr/lib/x86_64-linux-gnu/libstdc++.so.6 version GLIBCXX_3.4.18
+    #       sources:
+    #         - ubuntu-toolchain-r-test # if we don't specify this, the libstdc++6 we get is the wrong version
+    #       packages:
+    #         - libstdc++6
+    #         - fonts-droid
+    #   before_script:
+    #     - git clone https://github.com/flutter/flutter.git
+    #     - export PATH=`pwd`/flutter/bin:`pwd`/flutter/bin/cache/dart-sdk/bin:$PATH
+    #     - flutter doctor
+    #     - pub global activate flutter_plugin_tools
+    #   script:
+    #     - ./script/incremental_build.sh analyze
+     # Job 2) Run dart unit tests
+    - os: linux
+      env:
+        - SHARD=Format+Test
+      jdk: oraclejdk8
+      sudo: false
+      addons:
+        apt:
+          # Flutter depends on /usr/lib/x86_64-linux-gnu/libstdc++.so.6 version GLIBCXX_3.4.18
+          sources:
+            - ubuntu-toolchain-r-test # if we don't specify this, the libstdc++6 we get is the wrong version
+            - llvm-toolchain-precise # for clang-format-5.0
+          packages:
+            - libstdc++6
+            - fonts-droid
+            - clang-format-5.0
+      before_script:
+        - git clone --depth=1 https://github.com/flutter/flutter.git
+        - export PATH=`pwd`/flutter/bin:`pwd`/flutter/bin/cache/dart-sdk/bin:$PATH
+        - flutter doctor
+      script:
+        - flutter test
+    # Job 3.1) Build example APKs and run Java tests, shard 1/2
+    - os: linux
+      env:
+        - SHARD="Build example apks 1/2"
+        - PLUGIN_SHARDING="--shardIndex 0 --shardCount 2"
+      jdk: oraclejdk8
+      sudo: false
+      addons:
+        apt:
+          # Flutter depends on /usr/lib/x86_64-linux-gnu/libstdc++.so.6 version GLIBCXX_3.4.18
+          sources:
+            - ubuntu-toolchain-r-test # if we don't specify this, the libstdc++6 we get is the wrong version
+          packages:
+            - lib32stdc++6 # https://github.com/flutter/flutter/issues/6207
+            - libstdc++6
+            - fonts-droid
+      before_script:
+        - ./scripts/before_build_apks.sh
+        - export ANDROID_HOME=`pwd`/android-sdk
+        - export PATH=`pwd`/flutter/bin:`pwd`/flutter/bin/cache/dart-sdk/bin:$PATH
+        - export FLUTTER_HOME=`pwd`/flutter
+      script:
+        - cd example/android
+        - ./gradlew test -DflutterPath=$FLUTTER_HOME
+    # # Job 3.2) Build example APKs and run Java tests, shard 2/2
+    # - os: linux
+    #   env:
+    #     - SHARD="Build example apks 2/2"
+    #     - PLUGIN_SHARDING="--shardIndex 1 --shardCount 2"
+    #   jdk: oraclejdk8
+    #   sudo: false
+    #   addons:
+    #     apt:
+    #       # Flutter depends on /usr/lib/x86_64-linux-gnu/libstdc++.so.6 version GLIBCXX_3.4.18
+    #       sources:
+    #         - ubuntu-toolchain-r-test # if we don't specify this, the libstdc++6 we get is the wrong version
+    #       packages:
+    #         - lib32stdc++6 # https://github.com/flutter/flutter/issues/6207
+    #         - libstdc++6
+    #         - fonts-droid
+    #   before_script:
+    #     - ./script/before_build_apks.sh
+    #     - export ANDROID_HOME=`pwd`/android-sdk
+    #     - export PATH=`pwd`/flutter/bin:`pwd`/flutter/bin/cache/dart-sdk/bin:$PATH
+    #   script:
+    #     - ./script/incremental_build.sh build-examples --apk
+    #     - ./script/incremental_build.sh java-test  # must come after apk build
+
+
+cache:
+  directories:
+    - $HOME/.pub-cache