在Espresso android中获取当前活动
如果测试跨越多个活动,是否有方法获取当前活动 getActivtiy()方法只提供一个用于启动测试的活动 我试过下面的方法在Espresso android中获取当前活动,android,ui-automation,android-espresso,Android,Ui Automation,Android Espresso,如果测试跨越多个活动,是否有方法获取当前活动 getActivtiy()方法只提供一个用于启动测试的活动 我试过下面的方法 public Activity getCurrentActivity() { Activity activity = null; ActivityManager am = (ActivityManager) this.getActivity().getSystemService(Context.ACTIVITY_SERVICE); List<A
public Activity getCurrentActivity() {
Activity activity = null;
ActivityManager am = (ActivityManager) this.getActivity().getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
try {
Class<?> myClass = taskInfo.get(0).topActivity.getClass();
activity = (Activity) myClass.newInstance();
}
catch (Exception e) {
}
return activity;
}
公共活动getCurrentActivity(){
活动=空;
ActivityManager am=(ActivityManager)this.getActivity().getSystemService(Context.ACTIVITY_服务);
List taskInfo=am.getRunningTasks(1);
试一试{
类myClass=taskInfo.get(0.topActivity.getClass();
活动=(活动)myClass.newInstance();
}
捕获(例外e){
}
返回活动;
}
但是我得到了空对象。在浓缩咖啡中,您可以使用
ActivityLifecycleMonitorRegistry
,但它没有官方支持,因此在未来的版本中可能无法使用
以下是它的工作原理:
Activity getCurrentActivity() throws Throwable {
getInstrumentation().waitForIdleSync();
final Activity[] activity = new Activity[1];
runTestOnUiThread(new Runnable() {
@Override
public void run() {
java.util.Collection<Activity> activities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED);
activity[0] = Iterables.getOnlyElement(activities);
}});
return activity[0];
}
Activity getCurrentActivity()抛出可丢弃的{
getInstrumentation().waitForIdleSync();
最终活动[]活动=新活动[1];
runTestOnUiThread(新的Runnable(){
@凌驾
公开募捐{
java.util.Collection activities=ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.Resume);
活动[0]=Iterables.getOnlyElement(活动);
}});
返回活动[0];
}
如果您只需对照当前的活动进行检查,请使用may get God with native Espresso one liner检查是否启动了预期目的:
intended(hasComponent(new ComponentName(getTargetContext(), ExpectedActivity.class)));
// NOTE: make sure this is a strong reference (move up as a class field) otherwise will be GCed and you will not stably receive updates.
ActivityLifecycleCallback lifeCycleCallback = new ActivityLifecycleCallback() {
@Override
public void onActivityLifecycleChanged(Activity activity, Stage stage) {
classHolder.setValue(((MyActivity) activity).getClass());
// release the test thread
lock.countDown();
}
};
// used to block the test thread until activity is launched
final CountDownLatch lock = new CountDownLatch(1);
final Holder<Class<? extends MyActivity>> classHolder = new Holder<>();
instrumentation.runOnMainSync(new Runnable() {
@Override
public void run() {
ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(lifeCycleCallback);
}
});
// start the Activity
intent.setClassName(context, MyApp.class.getPackage().getName() + ".MyActivityAlias");
context.startActivity(intent);
// wait for activity to start
lock.await();
// continue with the tests
assertTrue(classHolder.hasValue());
assertTrue(classHolder.getValue().isAssignableFrom(MyActivity.class));
如果意式浓缩咖啡与你的不匹配,它也会同时向你展示你的意图
您需要的唯一设置是在测试中用IntentsTestRule
替换ActivityTestRule
,以便跟踪intent的启动。并确保此库位于您的build.gradle
依赖项中:
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.1'
公共静态活动getActivity(){
最终活动[]当前活动=新活动[1];
Espresso.onView(AllOf.AllOf(ViewMatchers.withId(android.R.id.content),isDisplayed()).perform(newviewaction()){
@凌驾
公共匹配器getConstraints(){
返回isAssignableFrom(View.class);
}
@凌驾
公共字符串getDescription(){
返回“从文本视图获取文本”;
}
@凌驾
公共作废执行(UiController UiController,视图){
if(view.getContext()活动实例){
Activity activity1=((Activity)view.getContext());
currentActivity[0]=activity1;
}
}
});
返回当前活动[0];
}
我喜欢@Ryan的版本,因为它不使用未记录的内部结构,但您可以编写更短的版本:
private Activity getCurrentActivity() {
final Activity[] activity = new Activity[1];
onView(isRoot()).check(new ViewAssertion() {
@Override
public void check(View view, NoMatchingViewException noViewFoundException) {
activity[0] = (Activity) view.getContext();
}
});
return activity[0];
}
请注意,但在Firebase测试实验室中运行测试时,这将不起作用。这会导致失败
java.lang.ClassCastException: com.android.internal.policy.DecorContext cannot be cast to android.app.Activity
如果测试用例中只有一个活动,则可以执行以下操作:
1.声明您测试规则
那是一块馅饼 在许多浓缩咖啡测试中,公认的答案可能不起作用。以下内容适用于在API 25设备上运行的espresso 2.2.2版和Android compile/target SDK 27:
@Nullable
private Activity getActivity() {
Activity currentActivity = null;
Collection resumedActivities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(RESUMED);
if (resumedActivities.iterator().hasNext()){
currentActivity = (Activity) resumedActivities.iterator().next();
}
return currentActivity;
}
@lacton提出的解决方案对我不起作用,可能是因为活动未处于ActivityLifecycleMonitorRegistry
报告的状态
我甚至尝试了阶段。PRE_ON_CREATE
仍然没有得到任何活动
注意:我无法使用ActivityTestRule
或intettestrule
,因为我正在使用activitiy别名启动我的活动,当我想测试别名是否工作时,在测试中使用实际类没有任何意义
我的解决方案是通过ActivityLifecycleMonitorRegistry
订阅生命周期更改,并在启动活动之前阻止测试线程:
intended(hasComponent(new ComponentName(getTargetContext(), ExpectedActivity.class)));
// NOTE: make sure this is a strong reference (move up as a class field) otherwise will be GCed and you will not stably receive updates.
ActivityLifecycleCallback lifeCycleCallback = new ActivityLifecycleCallback() {
@Override
public void onActivityLifecycleChanged(Activity activity, Stage stage) {
classHolder.setValue(((MyActivity) activity).getClass());
// release the test thread
lock.countDown();
}
};
// used to block the test thread until activity is launched
final CountDownLatch lock = new CountDownLatch(1);
final Holder<Class<? extends MyActivity>> classHolder = new Holder<>();
instrumentation.runOnMainSync(new Runnable() {
@Override
public void run() {
ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(lifeCycleCallback);
}
});
// start the Activity
intent.setClassName(context, MyApp.class.getPackage().getName() + ".MyActivityAlias");
context.startActivity(intent);
// wait for activity to start
lock.await();
// continue with the tests
assertTrue(classHolder.hasValue());
assertTrue(classHolder.getValue().isAssignableFrom(MyActivity.class));
//注意:确保这是一个强引用(作为类字段上移),否则将被GCed,您将无法稳定地接收更新。
ActivityLifecycleCallback lifeCycleCallback=新建ActivityLifecycleCallback(){
@凌驾
ActivityLifeCycleChanged上的公共无效(活动、阶段){
setValue(((MyActivity)activity.getClass());
//释放测试线程
锁。倒计时();
}
};
//用于在启动活动之前阻止测试线程
最终倒计时闩锁=新倒计时闩锁(1);
最终持有者我无法获得任何其他解决方案,因此我不得不这样做:
声明您的活动测试规则
:
@Rule
public ActivityTestRule<MainActivity> mainActivityTestRule =
new ActivityTestRule<>(MainActivity.class);
添加要向应用程序上下文注册以获取生命周期更新的帮助器方法:
private void monitorCurrentActivity() {
mainActivityTestRule.getActivity().getApplication()
.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(final Activity activity, final Bundle savedInstanceState) { }
@Override
public void onActivityStarted(final Activity activity) { }
@Override
public void onActivityResumed(final Activity activity) {
currentActivity[0] = activity;
}
@Override
public void onActivityPaused(final Activity activity) { }
@Override
public void onActivityStopped(final Activity activity) { }
@Override
public void onActivitySaveInstanceState(final Activity activity, final Bundle outState) { }
@Override
public void onActivityDestroyed(final Activity activity) { }
});
}
添加助手方法以获取当前活动
private Activity getCurrentActivity() {
return currentActivity[0];
}
因此,一旦您启动了第一个活动,只需调用monitorCurrentActivity()
,然后每当您需要当前活动的引用时,只需调用getCurrentActivity()
我改进了@Fabian Streitel answer,这样您就可以使用此方法而无需ClassCastException
public static Activity getCurrentActivity() {
final Activity[] activity = new Activity[1];
onView(isRoot()).check((view, noViewFoundException) -> {
View checkedView = view;
while (checkedView instanceof ViewGroup && ((ViewGroup) checkedView).getChildCount() > 0) {
checkedView = ((ViewGroup) checkedView).getChildAt(0);
if (checkedView.getContext() instanceof Activity) {
activity[0] = (Activity) checkedView.getContext();
return;
}
}
});
return activity[0];
}
Android团队已将ActivityTestRule
替换为。我们可以使用activityTestRule
执行activityTestRule.getActivity()
,但不能使用。以下是我的解决方案,用于从中获取活动
(灵感来自@Ryan和@Fabian solutions)
以下是用于访问当前活动的通用util的Kotlin版本:
class CurrentActivityDelegate(application: Application) {
private var cachedActivity: Activity? = null
init {
monitorCurrentActivity(application)
}
fun getCurrentActivity() = cachedActivity
private fun monitorCurrentActivity(application: Application) {
application.registerActivityLifecycleCallbacks(
object : Application.ActivityLifecycleCallbacks {
override fun onActivityResumed(activity: Activity) {
cachedActivity = activity
Log.i(TAG, "Current activity updated: ${activity::class.simpleName}")
}
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {}
override fun onActivityStarted(activity: Activity?) {}
override fun onActivityPaused(activity: Activity?) {}
override fun onActivityStopped(activity: Activity?) {}
override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {}
override fun onActivityDestroyed(activity: Activity?) {}
})
}
}
然后像这样简单地使用:
@Before
fun setup() {
currentActivityDelegate = CurrentActivityDelegate(activityTestRule.activity.application)
}
对espresso进行更新后,是否仍有可能为空?我目前根本无法从中获取非空值,但我曾经能够。将此代码用于espresso 2.0在Kotlin中有一个类似的解决方案:这种方法与AndroidX测试相关吗?您是否设法找到了Firebase测试实验室失败的原因?我不清楚他们为什么要这样做,但该视图并没有将活动作为其上下文,而是将其作为装饰
@get:Rule
var activityRule = ActivityScenarioRule(MainActivity::class.java)
...
private fun getActivity(): Activity? {
var activity: Activity? = null
activityRule.scenario.onActivity {
activity = it
}
return activity
}
class CurrentActivityDelegate(application: Application) {
private var cachedActivity: Activity? = null
init {
monitorCurrentActivity(application)
}
fun getCurrentActivity() = cachedActivity
private fun monitorCurrentActivity(application: Application) {
application.registerActivityLifecycleCallbacks(
object : Application.ActivityLifecycleCallbacks {
override fun onActivityResumed(activity: Activity) {
cachedActivity = activity
Log.i(TAG, "Current activity updated: ${activity::class.simpleName}")
}
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {}
override fun onActivityStarted(activity: Activity?) {}
override fun onActivityPaused(activity: Activity?) {}
override fun onActivityStopped(activity: Activity?) {}
override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {}
override fun onActivityDestroyed(activity: Activity?) {}
})
}
}
@Before
fun setup() {
currentActivityDelegate = CurrentActivityDelegate(activityTestRule.activity.application)
}