Использование Android UI Automator для тестирования контента на дополнительном дисплее - PullRequest
3 голосов
/ 02 октября 2019

У меня есть приложение barebones, написанное для проверки поддержки нескольких дисплеев. Моя установка представляет собой пользовательский планшет Android с ОС Android 8.1.0 («основной дисплей»), подключенный к сенсорному экрану («дополнительный дисплей») через HDMI (для передачи видеосигнала) и USB (для доставки сенсорных событий).

Приложение содержит одно действие, которое отображает «Hello World!»на основном дисплее, но также использует DisplayManager и WindowManager для добавления счетчика и двух кнопок + / - на дополнительном дисплее:

image

Running the app normally and interacting with the buttons on the secondary display works as expected.

Now, I want to use UI Automator скажем, нажмите кнопку + и убедитесь, что счетчик записывает правильное значение. Это кажется невозможным. Кто-нибудь знает, как я могу это сделать?

В качестве альтернативы, если UI Automator не является подходящим инструментом для работы, но есть какой-то другой инструмент, который позволит мне писать сквознойВ завершение тестов в стиле черного ящика для приложений, отображающих контент на дополнительном дисплее, я рад получить рекомендации.


Некоторые вещи, которые я исследовал

Я использовал uiautomatorviewer инструмент для проверки иерархии макетов моего приложения. С помощью этого инструмента отображается только содержимое основного дисплея:

enter image description here

Я использовал UiDevice.dumpWindowHierarchy(), чтобы получитьтекстовый дамп всего на устройстве. Выводится только содержимое основного устройства, хотя это включает информацию о системных окнах, таких как строка состояния и панель навигации.

Я использовал adb shell dumpsys window (с обоими tokens и windows команды). Этот покажет мне информацию об окне, которое я создал на дополнительном дисплее, но у меня, похоже, нет способа получить доступ к этому окну через Ui Automator:

Display #1
WindowToken{551f82f android.os.BinderProxy@87f65ac}:
  windows=[Window{e40e275 u0 com.example.stackoverflow}]
  windowType=2038 hidden=false hasVisible=true
Window #10 Window{20ac4ce u0 com.example.stackoverflow}:
  mDisplayId=1 mSession=Session{91fdd93 8079:u0a10089} mClient=android.os.BinderProxy@a3e65c9
  mOwnerUid=10089 mShowToOwnerOnly=true package=com.example.stackoverflow appop=SYSTEM_ALERT_WINDOW
  mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#20 ty=2038 fl=#1280480 colorMode=0}
  Requested w=1280 h=800 mLayoutSeq=908
  mBaseLayer=121000 mSubLayer=0 mAnimLayer=121000+0=121000 mLastLayer=121000
  mToken=WindowToken{a42e219 android.os.BinderProxy@a3e65c9}
  ...

Соответствующие примеры кода

Добавление содержимого на дополнительный дисплей (в методе моей деятельности onResume()):

DisplayManager manager = (DisplayManager) getApplicationContext().getSystemService(Context.DISPLAY_SERVICE);
Display display = manager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION)[0];
Context displayContext = getApplicationContext().createDisplayContext(display);
WindowManager windowManager = (WindowManager) displayContext.getSystemService(Context.WINDOW_SERVICE);

LinearLayout root = new LinearLayout(displayContext);
WindowManager.LayoutParams params = createLayoutParams();
windowManager.addView(root, params);

View.inflate(root.getContext(), R.layout.overlay, root);
root.findViewById(R.id.minus).setOnClickListener(v -> decrementCounter());
root.findViewById(R.id.plus).setOnClickListener(v -> incrementCounter());

Я использую контекст приложения вместо действияконтекст, чтобы содержимое на дополнительном дисплее не зависело от времени жизни действия, которое его создает. Теоретически я мог бы перейти к другим действиям, и этот контент оставался бы на дополнительном дисплее и оставался бы интерактивным.

Создание объекта LayoutParams:

private WindowManager.LayoutParams createLayoutParams() {
    return new WindowManager.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
            0, 0,
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
            0,
            PixelFormat.OPAQUE
    );
}

1 Ответ

0 голосов
/ 14 октября 2019

Существует Espresso , который работает для тестирования вашего приложения. Хорошо, что вам не нужно выбирать, что использовать. Вы можете использовать их обоих. Эспрессо работает в отдельном потоке, и это действительно быстро по сравнению с другими тестовыми средами. Используйте оба из них в своих тестах.

Эспрессо четко проверяет ожидания, взаимодействия и утверждения состояния, не отвлекаясь от типового содержимого, пользовательской инфраструктуры или беспорядочных подробностей реализации.

Эспрессо-тесты проходят оптимально быстро! Он позволяет вам оставлять свои ожидания, синхронизацию, спящие и опрашиваемые сообщения, пока он манипулирует и утверждает пользовательский интерфейс приложения, когда он находится в состоянии покоя.

Это Multiprocess Эспрессо, и этоэто шпаргалка для эспрессо.

Использование эспрессо с ActivityTestRule

В следующем разделе описывается, как создать новый тест эспрессо встиль JUnit 4 и используйте ActivityTestRule, чтобы уменьшить количество шаблонного кода, который вам нужно написать. Используя ActivityTestRule, среда тестирования запускает тестируемое действие перед каждым методом тестирования, аннотированным @Test, и перед любым методом, аннотированным @Before. Инфраструктура обрабатывает завершение действия после завершения теста и запуска всех методов, помеченных @After.

package com.example.android.testing.espresso.BasicSample;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;

@RunWith(AndroidJUnit4.class)
@LargeTest
public class ChangeTextBehaviorTest {

    private String stringToBetyped;

    @Rule
    public ActivityTestRule<MainActivity> activityRule
            = new ActivityTestRule<>(MainActivity.class);

    @Before
    public void initValidString() {
        // Specify a valid string.
        stringToBetyped = "Espresso";
    }

    @Test
    public void changeText_sameActivity() {
        // Type text and then press the button.
        onView(withId(R.id.editTextUserInput))
                .perform(typeText(stringToBetyped), closeSoftKeyboard());
        onView(withId(R.id.changeTextBt)).perform(click());

        // Check that the text was changed.
        onView(withId(R.id.textToBeChanged))
                .check(matches(withText(stringToBetyped)));
    }
}

А если вы хотите узнать больше, вот документация по тестированию 1027 *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...