Instrumentation test for Android - How to receive new Activity after orientation change?

…衆ロ難τιáo~ 提交于 2019-12-30 06:48:34

问题



I'm trying to test, if newly created Activity (after orientation change) is properly reinitialized. The code below shows that activity returned from getActivity() is the one constructed in setUp(), not the newly created one.

Test:

public class MyActivityTest extends ActivityInstrumentationTestCase2<MyActivity>{
 private static final String TAG = "RAMPS";
 private MyActivity mActivity;

 public MyActivityTest() {
    super("com.ramps", MyActivity.class);       
 }

 protected void setUp() throws Exception {
     super.setUp();
     mActivity = getActivity();
     Log.v(TAG, "setUp; activity=" + mActivity);
 }

public void testOrienationChange(){
     mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
     getInstrumentation().waitForIdleSync();
     MyActivity newActivity = getActivity(); //should be new, but it's not
     Log.v(TAG, "testOrienationChange; activity=" + newActivity);       
 }
}


Activiy:

public class MyActivity extends Activity {
    private static final String TAG = "RAMPS";  

 public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.v(TAG, "onCreate; activity=" + this);
    setContentView(new TextView(this));     
 }
    //...rest of stuff like onSaveInstanceState() etc.
}


And logs:

06-11 14:16:52.431: V/RAMPS(367): onCreate; activity=MyActivity@44eb8690
06-11 14:16:52.891: V/RAMPS(367): setUp; activity=MyActivity@44eb8690
06-11 14:16:52.971: V/RAMPS(367): onCreate; activity=MyActivity@44ee5178
06-11 14:16:53.131: V/RAMPS(367): testOrienationChange; activity=MyActivity@44eb8690


As mentioned before, logs shows that new activity is indeed created (MyActivity@44ee5178), but getActivity() return the old activity, created in setUp() (MyActivity@44eb8690). Is it possible to access newly created one?


回答1:


Ok, I think I finally managed to solve it - with robotium framework. I'm attaching the solution in case someone had the same problem.

Test:

public class MyActivityTest extends ActivityInstrumentationTestCase2<MyActivity>{

private static final String TAG = "RAMPS";
private MyActivity mActivity;
private Solo mSolo;

public MyActivityTest() {
    super("com.ramps", MyActivity.class);

}

@Override
protected void setUp() throws Exception {
    super.setUp();
    mActivity = getActivity();
    mSolo = new Solo(getInstrumentation(), getActivity());
    Log.v(TAG, "setUp; activity=" + mActivity);
}

public void testOrienationChange(){     
    mSolo.setActivityOrientation(Solo.LANDSCAPE);
    getInstrumentation().waitForIdleSync();
    MyActivity newActivity = getActivity(); //should be new, but it's not
    Activity newActivity2 = mSolo.getCurrentActivity(); //this will return new activity
    Log.v(TAG, "testOrienationChange; activity=" + newActivity);
    Log.v(TAG, "testOrienationChange; activity2=" + newActivity2);
}   

}

And log messages - for confirmation:

06-11 18:47:02.631: V/RAMPS(716): onCreate; activity=MyActivity@44c326a8
06-11 18:47:03.061: V/RAMPS(716): setUp; activity=MyActivity@44c326a8
06-11 18:47:03.781: V/RAMPS(716): onCreate; activity=MyActivity@44c481e0
06-11 18:47:04.482: V/RAMPS(716): testOrienationChange; activity=MyActivity@44c326a8
06-11 18:47:04.482: V/RAMPS(716): testOrienationChange; activity2=MyActivity@44c481e0

As you can see, activity returned from mSolo.getCurrentActivity() is the same that was created after orientation change. I really recommend Robotium - another great piece of code from Jayway!




回答2:


I've had the same problem in my UI tests. I don't use Robotium, but I created a new base test class with getActivity() that always returns current activity. The idea is to add an ActivityMonitor before orientation change and just update current activity on monitor wait:

public class UiTest<T extends Activity> extends ActivityInstrumentationTestCase2<T> {

private final Class<T> activityClass;
protected T activity;

public UiTest(Class<T> activityClass) {
  super(activityClass);
  this.activityClass = activityClass;
}

@Override
protected void setUp() throws Exception {
  super.setUp();
  setActivityInitialTouchMode(false);  // Depends on your needs.
  activity = super.getActivity();
  activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

/**
 * Rotates the test device and updates current activity.
 */
protected final void rotate() {
  int nextOrientation =
      activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
          ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
          : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
  Instrumentation.ActivityMonitor monitor =
      new Instrumentation.ActivityMonitor(activityClass.getName(), null, false);
  getInstrumentation().addMonitor(monitor);
  activity.setRequestedOrientation(nextOrientation);
  getInstrumentation().waitForIdleSync();
  this.activity = (T) getInstrumentation().waitForMonitor(monitor);
}

@Override
public T getActivity() {
  return activity;
}

Of course this won't work if activity class changes during the test or if orientation changes by other means, not with rotate() method. I hope this helps somebody.




回答3:


Instead of

 MyActivity newActivity = getActivity(); //should be new, but it's not

Try

MyActivity newActivity = instrumentation.startActivitySync(intent);

I think this method maybe help you




回答4:


Took @Smok's answer and updated it to always rotate:

@SuppressWarnings("unchecked") // it's fine
public static <T extends Activity> T rotate(ActivityInstrumentationTestCase2<T> testCase) {
    T activity = testCase.getActivity();
    int orientation = activity.getWindowManager().getDefaultDisplay().getRotation();
    int nextOrientation = orientation == Configuration.ORIENTATION_LANDSCAPE ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
    Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(activity.getClass().getName(), null, false);
    testCase.getInstrumentation().addMonitor(monitor);
    activity.setRequestedOrientation(nextOrientation);
    testCase.getInstrumentation().waitForIdleSync();
    return (T) testCase.getInstrumentation().waitForMonitor(monitor);
}

This fixes the problem of the orientation returning UNSPECIFIED




回答5:


This solved my issue, using only the Android testing framework:

    mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    mActivity.finish();
    setActivity(null);
    mActivity = getActivity();
    getInstrumentation().waitForIdleSync();

AFAIK, getActivity() does create a new activity if the current one is null which is done by setting it with setActivity(null). Also, the new activity will have the orientation set by Activity.setRequestedOrientation(int).

If you need to check whether the state is being correctly saved when orientation changes, you should call getInstrumentation().callActivityOnCreate(mActivity, Bundle) from the UI thread.



来源:https://stackoverflow.com/questions/10982370/instrumentation-test-for-android-how-to-receive-new-activity-after-orientation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!