我正在尝试使用espresso框架为Android APP编写一些UI测试。
现在我只是检查启动画面上是否存在所有元素,然后我尝试点击登录按钮。
单击该按钮时,测试失败,因为我无法理解为什么会发生错误。
我的测试代码是
@RunWith(AndroidJUnit4.class)
@SmallTest
public class WelcomeTest {
@Rule
public ActivityTestRule<Welcome> mActivityRule = new ActivityTestRule<>(
Welcome.class);
@Test
public void elements_present() {
// Check login
onView(withId(R.id.wv_login)).check(matches(isDisplayed()));
// Check signup
onView(withId(R.id.wv_signup)).check(matches(isDisplayed()));
// Check video
onView(withId(R.id.videoView)).check(matches(isDisplayed()));
// Check swipe right
onView(withId(R.id.videoView)).perform(swipeRight());
// Check swipe left
onView(withId(R.id.videoView)).perform(swipeLeft());
}
@Test
public void tap_login() {
// Tap login button
onView(withId(R.id.wv_login)).perform(click());
}
}
我得到的输出是:
引起:java.lang.RuntimeException:由于目标视图与以下一个或多个约束不匹配,因此不会执行操作: 至少90%的视图区域会显示给用户。
这是什么意思,这是由我的测试方法引起的还是代码中的错误?该应用似乎在我的设备上运行良好。
PS:我已经禁用动画,因为espresso文档建议
答案 0 :(得分:10)
引起:java.lang.RuntimeException:不会执行操作 因为目标视图与以下一个或多个不匹配 约束:显示至少90%的视图区域 用户。
当任何预期的视图未完全可见时,我会发生这种情况,默认情况下,Espresso正在寻找在设备屏幕上完全可见的元素。
似乎您的实际设备屏幕不显示您的登录活动xml文件的全部内容。
ScrollView
还是ListView
? 这可能会有所帮助:
onView(withId(R.id.wv_login))
.perform(scrollTo(), click());
我的问题仍然会发生,请您添加问题xml或截图。我会解决它; - )
注意:检查某些东西是否完全可见(这意味着更多 90%)你可以使用
onView(withId(R.id.wv_login)).check(matches(isCompletelyDisplayed()));
而不是:
onView(withId(R.id.wv_login)).check(matches(isDisplayed()));
在更大的屏幕设备上运行测试,检查它是否仍然存在。
如果您有疑问,请随意提问
答案 1 :(得分:2)
此处RuntimeException
显示的java.lang.RuntimeException: Action will not be performed because the target view does not match one or more of the following constraints: at least 90 percent of the view's area is displayed to the user.
实际上来自View
无法完全显示。然而,@ piotrek1543给出的答案并没有真正找到解决方案,尽管它充满了非常好的信息。
问题是由竞争条件引起的。您正在尝试打开视图,在打开视图期间,您尝试单击它。如果时机不对,那么View
中只有不到90%的Es click()
可用于Developer Options
。您可以按The Espresso Setup Instructions
Transition Animation Scale
我自己的测试表明,只需将0.0x
设置为 $("#jqGridDel").jqGrid({
url: "Data.aspx/BindInfo",
datatype: 'json',
mtype: 'POST',
serializeGridData: function (postData) {
return JSON.stringify(postData);
},
ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
ajaxSelectOptions: { type: 'POST',
contentType: 'application/json; charset=utf-8',
success: function (result) {
alert("hello");
}
},,
colName: ['DelId', 'Name', 'DeliveryName', 'Status'],
colModel: [
{
label: 'Del No',
name: 'DelId',
width: 35
},
{
label: 'Gate',
name: 'Name',
width: 200,
editable: true,
edittype: "select",
foramtter: "Select",
editoptions: {
dataUrl: "Data.aspx/BindDDInfo",
buildSelect: function (data)
{
alert(data);
}
}
},
{
label: 'Delivery',
name: 'DeliveryName',
width: 150,
editable: true
},
{
label: 'Active',
name: 'Status',
width: 40,
editable: true,
align: "center",
formatter: "checkbox",
edittype: "checkbox",
editoptions: { value: '1:0' }
}
],
loadonce: true,
width: 1050,
height: "100%",
pager: "#jqGridDelPager",
caption: "Configuration",
rowNum: 15,
jsonReader: {
page: function (obj) { return 1; },
total: function (obj) { return 1; },
records: function (obj) { return obj.d.length; },
root: function (obj) { return obj.d; },
repeatitems: false,
id: "QGDelId"
},
onSelectRow: function (id) {
if (id && id !== lastSelQGDel) {
lastSelQGDel = id;
}
},
ajaxRowOptions: { contentType: 'application/json; charset=utf-8' },
serializeRowData: function (postData) {
return JSON.stringify({ editQGData: postData });
},
editurl: "Data.aspx/SaveData"
});
$('#jqGridDel').navGrid("#jqGridDelPager", { edit: false, add: false, del: false, refresh: false, search: false, view: false });
$('#jqGridDel').inlineNav('#jqGridDelPager',
// the buttons to appear on the toolbar of the grid
{
edit: true,
add: true,
del: true,
refresh: true,
cancel: true,
editParams: {
keys: true,
rowid: lastSelQGDel,
restoreAfterError: true,
reloadAfterSubmit: true,
successfunc: function (result) {
if (result.responseJSON.d == "Success")
alert("Data saved successfully!!");
else
alert("There is some error in data processing");
setTimeout(function () {
$("#jqGridDel").jqGrid('setGridParam', { datatype: 'json' }).trigger('reloadGrid');
}, 50);
}
},
addParams: {
keys: true,
addRowParams: {
successfunc: function (result) {
if (result.responseJSON.d == "Success")
alert("Data saved successfully!!");
else
alert("There is some error in data processing");
setTimeout(function () {
$("#jqGridDel").jqGrid('setGridParam', { datatype: 'json' }).trigger('reloadGrid');
}, 50);
}
}
}
即可。您可以想象,这是您正在经历的竞争条件的完美一致的解决方案。
答案 2 :(得分:0)
如果未将按钮放置在滚动视图中并且关闭了动画,则当将按钮设置为高度并且在高度设置为wrap_content的父布局中时,会发生此错误。
失败
<LinearLayout
...
android:layout_width="match_parent"
**android:layout_height="wrap_content">**
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_attendance"
app:backgroundTint="@color/surveyColor"
android:textAllCaps="false"
android:text="View Attendance"
android:layout_weight="1"
android:layout_marginRight="5dp"
android:layout_width="0dp"
**android:layout_height="60dp"/>**
</LinearLayout>
Pass:高度值应该传递给父级布局
<LinearLayout
...
android:layout_width="match_parent"
**android:layout_height="60dp">**
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_attendance"
app:backgroundTint="@color/surveyColor"
android:textAllCaps="false"
android:text="View Attendance"
android:layout_weight="1"
android:layout_marginRight="5dp"
android:layout_width="0dp"
**android:layout_height="60dp"/>**
</LinearLayout>