Dav*_*jak 11 android android-activity android-testing android-instrumentation android-uiautomator
我想运行一个参数化的Instrumentation Test,它具有不同的语言环境,可以使用所有支持的语言运行相同的测试.
观察到的行为是,对于每个后续运行,活动都将具有第一次测试运行的本地化标题.因此,无论我的手机使用哪种语言,标题都将针对第一个参数化测试运行进行正确本地化,并且对于每个后续版本仍然相同.
虽然覆盖区域设置本身适用于任何资源,它会工作只有一次的活动标题,如果设置由AndroidManifest.xml.
活动似乎得到了他们的标题设置attach,无论调用附件似乎是缓存应用程序首次启动的区域设置中的标题.
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
---> CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
Run Code Online (Sandbox Code Playgroud)
由于资源总是被正确地本地化,因此解决方法是调用setTitle(R.string.title)或只是getActionBar().setTitle(R.string.setTitle),但我不想仅为了测试目的而更改活动.
问题:如何在第一次测试运行后更改活动的标题?如上所述,这似乎被缓存并且没有正确更新,并且杀死应用程序以重新启动它将无法进行检测测试.
整个测试项目可以在GitHub上找到(Localization.java包含当前失败的单元测试和此处描述的问题)并且正在使用参数化单元测试UIAutomator.
我们的目标是在不了解应用程序本身(UIAutomator)的情况下拍摄一批截图,并且不需要为测试修改应用程序.
我在每次测试之前都成功地更改了语言环境,并通过执行以下操作正确显示了我的文本,同时我还有多个断言确保资源实际上是正确的语言环境.
public LocalizationTest(Locale locale) {
mLocale = locale;
Configuration config = new Configuration();
Locale.setDefault(mLocale);
config.setLocale(mLocale);
Resources resources = InstrumentationRegistry.getTargetContext().getResources();
resources.updateConfiguration(config, resources.getDisplayMetrics());
resources.flushLayoutCache();
}
Run Code Online (Sandbox Code Playgroud)
我显然尝试在目标上下文,应用程序上下文和活动上以相同的方式设置语言环境(反正可能为时已晚).
我看到它attach被调用Instrumentation,但只是创建一个新的App并尝试启动活动也不会本地化标题.
Intent intent = context.getPackageManager().getLaunchIntentForPackage(BuildConfig.APPLICATION_ID);
context = InstrumentationRegistry.getInstrumentation().newApplication(App.class,
InstrumentationRegistry.getTargetContext());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
Run Code Online (Sandbox Code Playgroud)
ApplicationPackageManager标题字符串以static 形式缓存在包管理器中sStringCache。
虽然有一种方法static void configurationChanged()可以清除缓存,但它似乎不会在手动更改时被调用。因此,所描述的问题是在第一次调用后活动标题本地化错误。
解决这个问题的方法是使用反射来加载类并自行调用方法。这有点脏,因为它正在访问私有方法,但它有效。
// as before
Configuration config = new Configuration();
Locale.setDefault(mLocale);
config.setLocale(mLocale);
Resources resources = context.getResources();
resources.updateConfiguration(config, resources.getDisplayMetrics());
// CLEAR the cache!
Method method = getClass().getClassLoader()
.loadClass("android.app.ApplicationPackageManager")
.getDeclaredMethod("configurationChanged");
method.setAccessible(true);
method.invoke(null);
Run Code Online (Sandbox Code Playgroud)
或者,您可以在另一个非公共 API 上使用公共方法,该 API 反过来也会调用上述方法。仍然很脏,但不调用私有方法。
看来您可以resources.updateConfiguration(...);通过使用此方法来省略,因为它也会解决这个问题。
// Clear the cache.
Object thread = getClass().getClassLoader()
.loadClass("android.app.ActivityThread")
.getMethod("currentActivityThread")
.invoke(null);
Method method = getClass().getClassLoader()
.loadClass("android.app.ActivityThread")
.getMethod("applyConfigurationToResources", Configuration.class);
method.invoke(thread, config);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
339 次 |
| 最近记录: |