我有一个简单的应用程序,用来测试对多个显示器的支持。我的安装是一个定制的Android平板电脑,运行Android8.1.0(“主显示器”),通过HDMI (传送视频信号)和USB (传递触摸事件)连接到触摸屏(“二级显示”)。
这个应用程序包含一个活动,显示"Hello!“在主显示器上,还利用DisplayManager和WindowManager向辅助显示器添加计数器和两个+ / -按钮:

正常运行应用程序并与辅助显示上的按钮进行交互,就像预期的那样。
现在,我希望使用UI自动机来单击+按钮,并验证计数器是否记录了正确的值。这似乎是不可能的。有人知道我是怎么做到的吗?
或者,如果UI Automator不是适合这项工作的工具,但是还有其他一些工具可以让我为在二次显示上显示内容的应用程序编写端到端的黑匣子风格的测试,我很高兴得到推荐。
我调查过的一些事情
我使用了uiautomatorviewer工具来检查应用程序的布局层次结构。只有主显示器上的内容可用此工具显示:

我使用UiDevice.dumpWindowHierarchy()获取设备上所有内容的文本转储。仅转储主设备上的内容,尽管这包括有关系统窗口(如状态栏和导航栏)的信息。
我使用了adb shell dumpsys window (包括tokens和windows命令)。此将向我展示有关我在辅助显示器上创建的窗口的信息,但我似乎无法通过information访问此窗口:
Display #1
WindowToken{551f82f android.os.BinderProxy@87f65ac}:
windows=[Window{e40e275 u0 com.example.stackoverflow}]
windowType=2038 hidden=false hasVisible=trueWindow #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
);
}发布于 2019-10-14 20:48:59
还有浓缩咖啡,它可以用来测试你的应用程序。好的是,你没有选择使用哪一种。你可以同时使用它们。Espresso在单独的线程中运行,与其他测试框架相比,它非常快速。在你的测试中使用它们。
Espresso清楚地测试状态期望、交互和断言,而不受样板内容、自定义基础结构或混乱的实现细节的干扰。 浓缩咖啡测试运行速度最佳!它允许您将等待、同步、睡眠和轮询抛在后面,而当应用程序UI处于静止状态时,它会对其进行操作和断言。
这是Espresso的多进程,这是Espresso的备忘单。
与ActivityTestRule一起使用Espresso
下面一节描述如何以JUnit 4样式创建新的Espresso测试,并使用ActivityTestRule来减少您需要编写的样板代码的数量。通过使用ActivityTestRule,测试框架在每个带有@Test注解的测试方法之前和任何带有@ any注释的方法之前启动测试活动。该框架负责在测试结束后关闭活动,并运行所有带有@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)));
}
}如果你想了解更多,这里是测试文件
https://stackoverflow.com/questions/58209133
复制相似问题