Подтвердить что ты не робот

Тестирование жизненного цикла нагрузки

В действии unit test как я могу эмулировать события жизненного цикла активности.

Я могу вызвать методы callationActivityOn... для существующей деятельности, но как активировать активность, чтобы активность OnCreate получала пакет с сохраненным состоянием

4b9b3361

Ответ 1

Я обнаружил, что этот код вызывает создание нового Activity:

myActivity.finish();
setActivity(null);
myActivity = getActivity();

Но это не вызывает вызов onSaveInstanceState. Так, например, чтобы проверить, действительно ли активность создана после изменения ориентации представления, такой тест должен сделать это:

private mInstrumentation = getInstrumentation();
...
final Bundle outState = new Bundle();
mInstrumentation.callActivityOnSaveInstanceState(mActivity, outState);
mActivity.finish();
setActivity(null);
mActivity = getActivity();
runTestOnUiThread(new Thread() {
    @Override
    public void run() {
        mInstrumentation.callActivityOnRestoreInstanceState(mActivity, outState);
    }
});

Ответ 2

Не следуйте примеру примера управления состоянием: {dead link}

myActivity.finish();
myActivity = getActivity();

ActivityInstrumentationTestCase2.getActivity() запускает действие при первом вызове, но затем он просто возвращает ту же самую активность в каждом последующем вызове в тестовом примере. Таким образом, вы все еще смотрите на завершенную работу.

После завершения первого действия вам нужно запустить новый тест. Например, вы можете использовать InstrumentationTestCase.launchActivity().

В качестве другого примера я написал тест, который нажимает кнопку в ActivityA, которая запускает ActivityB for-result; тест затем сразу же убивает ActivityA (с помощью изменения ориентации, но функция finish() тоже будет работать), а затем тест получает дескриптор новой ActivityA, создаваемой системой, когда ActivityB выполняется и отправляет свой результат. Трюк заключался в том, чтобы провести тест, добавив Instrumentation.ActivityMonitor, а затем, чтобы этот монитор подождал, когда система запустит новую ActivityA и даст ему тестовый дескриптор.

EDIT 2/23/2012 cdhabecker, добавление воспроизводимого кода:

public class VerboseActivity extends Activity {
    public final static String TAG = "Verbose";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "onCreate() " + (Activity)this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity5);
    }
    @Override
    protected void onDestroy() {
        Log.i(TAG, "onDestroy().");
        super.onDestroy();
    }
}

Тестовый случай: (вызовы sleep() дают активности много времени для ответа)

public class VerboseTest extends
        ActivityInstrumentationTestCase2<VerboseActivity> {

    Activity myActivity = null;

    public VerboseTest() {
        super("com.scanillion.demo", VerboseActivity.class);
    }

    public void test_01() {
        String TAG = "test_01";
        myActivity = getActivity();
        Log.i(TAG, "A getActivity()=" + myActivity);
        myActivity.finish();
        try {
            Thread.sleep(5000L);
        } catch (InterruptedException e) {
        }
        myActivity = getActivity();
        Log.i(TAG, "B getActivity()=" + myActivity);
        try {
            Thread.sleep(5000L);
        } catch (InterruptedException e) {
        }
    }
}

Log:

02-23 21:25:37.689: I/Verbose(17747): onCreate() [email protected]
02-23 21:25:38.159: I/ActivityManager(67): Displayed activity com.scanillion.demo/.VerboseActivity: 526 ms (total 526 ms)
02-23 21:25:38.180: I/test_01(17747): A getActivity()[email protected]
02-23 21:25:38.540: I/Verbose(17747): onDestroy().
02-23 21:25:43.236: I/test_01(17747): B getActivity()[email protected]
02-23 21:25:48.439: I/TestRunner(17747): finished: test_01(com.scanillion.demo.test.VerboseTest)
02-23 21:25:48.439: I/TestRunner(17747): passed: test_01(com.scanillion.demo.test.VerboseTest)

Обратите внимание, что finish() вызвало onDestroy(), но последующий getActivity() был не-op. Мало того, что getActivity() не создает экземпляр нового действия, он даже не воссоздает оригинал.

Ответ 3

Я подтверждаю, что cdhabecker прав, getActivity() возвращает активность, которая была создана в начале, даже если вы "закончили" ее. Но я думаю, что нашел решение для проверки активности. Вы можете попытаться запросить изменение ориентации. Это заново воссоздает вашу деятельность, а затем вы получите вновь созданную. Ниже приведен фрагмент кода: (я использовал robotium):

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 not
  Activity newActivity2 = mSolo.getCurrentActivity(); //this will return newly created
  Log.v(TAG, "testOrienationChange; activity=" + newActivity);
  Log.v(TAG, "testOrienationChange; activity2=" + newActivity2);
}   

Конечно, это не сработает, если вы не сможете уничтожить свою деятельность после изменения ориентации. Здесь вы можете найти мой полный ответ с включенными сообщениями журнала. Надеюсь, это поможет. С уважением!

Ответ 4

Если у вас есть устройство Android 4.x, вы можете войти в Настройки > Параметры разработчика и ПРОВЕРИТЬ "Не выполнять действия". Теперь, когда ваша активность теряет фокус (например: кнопка HOME), она будет убита и вызывается onSaveInstanceState (...).

Когда вы возобновляете свое приложение, ваша активность должна иметь связанные данные в методе onCreate (...), если вы сохранили его в onSaveInstanceState (...).

Ответ 5

В официальном руководстве разработчиков есть очень хороший пример, говорящий о тестах государственного управления здесь. В основном вам просто нужно вызвать Activity.finish() для эмуляции активности, был убит, посмотрите псевдо-код ниже:

public void testIfStateIsSaved() {
  // Open myActivity first time.
  MyActivity myActivity = getActivity();
  final EditText editText = (EditText) myActivity.findViewById(com.company.R.id.edit_text);
  // emulate some user action
  myActivity.runOnUiThread(new Runnable() {
    public void run() {
      editText.setText("save me");
    }
  });

  // Suppose you have implemented saved state properly.

  // kill activity and restart it again.
  myActivity.finish();
  myActivity = getActivity();
  final EditText editText2 = (EditText) myActivity.findViewById(com.company.R.id.edit_text);
  assertEquals("user input must be saved", "save me", editText2.getText());
}

Надеюсь, что это поможет.

Ответ 6

Разрабатывая ответ cdhabecker, я создал следующий статический метод, который работает для меня:

public static Activity restartActivity(Activity activity, Instrumentation instrumentation, Intent intent){
    String className = activity.getClass().getName();
    Instrumentation.ActivityMonitor monitor = instrumentation.addMonitor(className, null, false);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setClassName(instrumentation.getTargetContext(), className );
    instrumentation.startActivitySync(intent);
    Activity newActivity = instrumentation.waitForMonitor(monitor);
    instrumentation.removeMonitor(monitor);
    return newActivity;
}

После использования операции я уничтожаю его и reset, вызывая

activity.finish();
setActivity(null);

в классе ActivityInstrumentationTestCase2.

Ответ 7

Вы можете получить новую возобновленную активность через ActivityLifeCycleMonitor

Например, этот метод ждет и устанавливает новый созданный Activity как текущий Activity.

public void waitAndSetResumedActivity() {
    // well at least there are some activities in the pipeline - lets see if they resume.

    long[] waitTimes =
            {10, 50, 100, 500, TimeUnit.SECONDS.toMillis(2), TimeUnit.SECONDS.toMillis(30)};

    final ActivityLifecycleMonitor activityLifecycleMonitor = ActivityLifecycleMonitorRegistry.getInstance();
    final AtomicBoolean activityResumed = new AtomicBoolean(false);
    for (int waitIdx = 0; waitIdx < waitTimes.length; waitIdx++) {
        if (activityResumed.get()) return;
        try {
            Thread.sleep(waitTimes[waitIdx]);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        getInstrumentation().runOnMainSync(new Runnable() {
            @Override
            public void run() {
                Collection<Activity> resumedActivities = activityLifecycleMonitor.getActivitiesInStage(Stage.RESUMED);
                if (!resumedActivities.isEmpty()) {
                    activity = (MainActivity) resumedActivities.iterator().next();
                    setActivity(activity);
                    activityResumed.set(true);
                }
            }
        });

    }
    throw new NoActivityResumedException("No activities in stage RESUMED. Did you forget to "
            + "launch the activity. (test.getActivity() or similar)?");

}

Поэтому после вызова этого метода любой вызов getActivity() будет возвращать новое действие.

Вы можете протестировать активность в режиме ротации следующим образом:

Activity activity = getActivity(); // old activity    
//rotate it
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
//set new Activity
waitAndSetResumedActivity();
activity = getActivity();  // New Activity