如何在Android Oreo中为Espresso测试禁用新的Autofill功能

28

在使用 sdk 26 的 Android 设备上运行测试会导致测试失败,因为新的 Autofill 功能会在 Espresso 尝试单击字段时隐藏它们。

我正在 Firebase 测试实验室上运行我的测试,所以我无法在我的测试设备上手动禁用它们。

一些图片:

1. 在单击用户名字段之前,密码是可见的。

enter image description here

2. 单击用户名字段后,此 Autofill 对话框会隐藏密码字段:

enter image description here

3. 登录后显示另一个填充对话框:

enter image description here

现在 Espresso 无法单击密码字段,因为 Autofill 对话框隐藏了我的字段并且 fail

使用 AutofillManager#disableAutofillServices() 只会禁用 #2. 对话框,但 #3. 仍然存在。

如何在测试设备上禁用 Autofill?


{btsdaf} - CommonsWare
3
@CommonsWare 我无法从云端(如Firebase)访问设备上的设置,因此我需要在测试运行之前通过代码禁用它们。 - Daniel Gomez Rico
你找到答案了吗?同样的问题。 - Anton Shkurenko
嘿,你找到任何解决方案了吗?下面的答案对我关闭电子邮件/密码自动填充建议框(截图#2)没有用,测试也失败了。 - Priyanka
1
我认为这不是一个好的做法,你修改了生产代码以便进行测试,这增加了可能出现故障的风险,同时也暴露了测试存在的知识,请将此记在心中将来。 - Daniel Gomez Rico
显示剩余5条评论
8个回答

14
根据文档,您可以使用 AutofillManager#disableAutofillServices() API 来禁用自动填充服务:

如果调用此 API 的应用程序已启用了自动填充服务,则它们将被禁用。

使用方法:


    val autofillManager: AutofillManager = context.getSystemService(AutofillManager::class.java)
    autofillManager.disableAutofillServices()

您可以在测试的 @Before 步骤中执行此操作。


(注: AutuFill服务是一种Android平台提供的自动填充功能,可以加快用户完成表格和其他输入操作的速度。禁用这项服务可以在测试期间保证应用程序的准确性。)

1
它移除了“点击以使用Google”对话框,但仍然显示“保存密码到使用Google自动填充”的对话框。 - Daniel Gomez Rico
1
我没有O设备,也找不到模拟器中的“使用Google自动填充”应用程序。我认为在执行仪器化测试时,你可以尝试通过adb shell命令来禁用该应用程序(如何?):adb shell pm disable package.name.of.autofill.with.google - azizbekian
你可以在 Android O 模拟器的“设置”中找到它。 - Daniel Gomez Rico

12

adb shell pm disable com.google.android.gms/com.google.android.gms.autofill.service.AutofillService

这会禁用自动填充服务。这等同于在系统设置中手动关闭自动填充服务。至少在模拟器上可以运行。但这需要root权限。

另一种禁用自动填充服务的方法是更改autofill_service设置。

adb shell settings put secure autofill_service null


3
最后一个命令 adb shell settings put secure autofill_service null 生效了!谢谢! - Daniel Gomez Rico
可以添加代码来重新启用它吗?在“...autofill_service null”之后 :) - Anton Shkurenko
我通过将“null”更改为“com.google.android.gms/com.google.android.gms.autofill.service.AutofillService”来启用它,谢谢 :) - Anton Shkurenko
截至2023年5月25日,此方法已不再有效:sudo adb shell设置put secure autofill_service null在执行“put”时发生异常:java.lang.SecurityException:权限拒绝:写入设置需要:android.permission.WRITE_SECURE_SETTINGS - FractalBob

7
一个基于@Alan K解决方案的备选代码组织方式。
创建DisableAutofillAction类:
public class DisableAutofillAction implements ViewAction {

    @Override
    public Matcher<View> getConstraints() {
        return Matchers.any(View.class);
    }

    @Override
    public String getDescription() {
        return "Dismissing autofill picker";
    }

    @Override
    public void perform(UiController uiController, View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            AutofillManager autofillManager = view.getContext().getSystemService(AutofillManager.class);

            if (autofillManager != null) {
                autofillManager.cancel();
            }
        }
    }
}

当你需要禁用editTextPassword的AutoFill功能时,可以在代码中进行如下设置:

editTextPassword.perform(..., ViewActions.closeSoftKeyboard(), DisableAutofillAction())

4
以下代码段可用于忽略新的Android建议:
getWindow().getDecorView().setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);

3

我在Espresso测试中成功禁用了自动填充功能,通过应用自定义的ViewActions来实现当输入文本时。

            .onView(...)
            .perform(
                    new ViewAction() {
                        @Override
                        public Matcher<View> getConstraints() {
                            return Matchers.any(View.class);
                        }

                        @Override
                        public String getDescription() {
                            return "Marking view not important for autofill";
                        }

                        @Override
                        public void perform(UiController uiController, View view) {
                            // Required to disable autofill suggestions during tests on API 26+
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                                view.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO);
                            }
                        }
                    })
            .perform(click())
            .perform(clearText())
            .perform(typeText(textToType))
            .perform(
                    new ViewAction() {
                        @Override
                        public Matcher<View> getConstraints() {
                            return Matchers.any(View.class);
                        }

                        @Override
                        public String getDescription() {
                            return "Dismissing autofill picker";
                        }

                        @Override
                        public void perform(UiController uiController, View view) {
                            // Required to dismiss the autofill picker during tests on API 26+
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                                AutofillManager autofillManager =
                                        view.getContext()
                                                .getSystemService(AutofillManager.class);
                                if (autofillManager != null) autofillManager.cancel();
                            }
                        }
                    });

-1
在您的设备中,前往以下路径 设置 > 系统 > 语言和输入 > 高级 > 自动填充服务,然后取消它。

1
如果您可以访问您的设备,那么这将起作用,但对于测试设备农场和更自动化的东西则不适用,请阅读问题文本。 - Daniel Gomez Rico

-1

根据文档说明 : 当视图聚焦并且是数据集的一部分时,应用程序可以通过使用registerCallback(AutofillCallback)注册AutofillManager.AutofillCallback来在显示适当操作时接收通知。当用户从适当操作中选择一个数据集时,通过对autofill(AutofillValue)或autofill(SparseArray)的调用自动填充数据集中所有存在的视图。

当满足以下条件之一时,上下文将结束:

  1. 调用commit()或所有可保存的视图都消失了。
  2. 调用cancel()。

可以从任何线程调用此类的方法。

必须使用Context.getSystemService(Class)方法和参数AutofillManager.class获取此类的实例。

使用disableAutofillServices() 方法来禁用该服务。


请阅读问题,我已经说过这种情况不适用。 - Daniel Gomez Rico

-1

在测试时禁用自动填充。在Gradle中定义一个TestRunner类。

defaultConfig {
    testInstrumentationRunner "com.cover.android.TestRunner"
}

那么

public class TestRunner extends AndroidJUnitRunner {

  @Override
  public void onCreate(Bundle arguments) {
      super.onCreate(arguments);
      CustomEditText.TESTING = TRUE;
  }
}

然后使用自定义版本的EditText

public class CustomEditText extends AppCompatEditText {
public static boolean TESTING = false;
public CustomEditText(Context context) {
    super(context);
}

@Override
public int getAutofillType() {
    return TESTING? AUTOFILL_TYPE_NONE : super.getAutofillType();
}

3
因为这个目的而改变我应用程序中的所有“EditText”感觉不好,但还是谢谢。 - Daniel Gomez Rico

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接