Android JUnit测试首选项(Android JUnit testing of Preferences)

一个相当正常的场景:Android应用程序具有首选项活动,并且从ListPreference中选择一个选项会触发代码以更改该ListPreference的摘要文本。 即:从颜色ListPreference中选择“绿色”将通过onPreferenceChange回调将ListPreference的摘要文本更改为“绿色”。

我希望能够使用Android JUnit测试来确认这些摘要更改都正确执行。 但是,关于如何做到这一点的信息似乎很少。

我已尝试在ListPreference上使用setValue()各种变体,无论是在测试线程还是通过runOnUiThread() ,都没有成功 - 这不会触发对onPreferenceChange()的调用。 我在调用setValue()之后也尝试了getInstrumentation().waitForIdleSync() setValue() ,但这也没有成功。

所以,我的问题是:这是怎么做到的?

谢谢!

A fairly normal scenario: an Android application has a preferences activity, and selecting an option from a ListPreference triggers code to change that ListPreference's summary text. ie: Selecting "Green" from a color ListPreference would change the ListPreference's summary text to "Green" through a onPreferenceChange callback.

I'd like to be able to use the Android JUnit testing to confirm that these summary changes are all being performed correctly. However, there seems to be very little information out there on how to do this.

I've tried variations of using setValue() on ListPreference, both in the test thread and through runOnUiThread(), with no success - this doesn't trigger the call to onPreferenceChange(). I've also tried getInstrumentation().waitForIdleSync() after calling setValue(), but that's also with no success.

So, my question is: how is this done?

Thanks!

最满意答案

几个小时的工作产生了这个工作解决方案,但我很好奇其他人是否有更好的解决方案。 这个代码的灵感来自这个类似问题的解决方案 ,但这种情况在两个方面有所不同:

它适用于Android JUnit,这意味着它需要通过runOnUiThread()调用ListPreference UI点击。 它预计会有使用的偏好类别,这使得查找位置(相对于整个首选项列表)变得复杂。 上述解决方案仅适用于没有偏好类别的情况。

此方法将接受特定ListPreference项的键,以及要单击的列表中项的位置。 然后它将执行该列表项单击,其他代码将执行我正在寻找的检查。

请注意,这需要setActivityInitialTouchMode(true); 在setUp()方法中调用getActivity()之前设置。

private void clickListPreference(String _listPreferenceKey, int _listItemPos){ final String listPreferenceKey = _listPreferenceKey; final int listItemPos = _listItemPos; mActivity.runOnUiThread( new Runnable() { public void run() { // get a handle to the particular ListPreference ListPreference listPreference= (ListPreference) mActivity.findPreference(listPreferenceKey); // bring up the dialog box mActivity.getPreferenceScreen().onItemClick( null, null, getPreferencePosition(), 0 ); // click the requested item AlertDialog listDialog = (AlertDialog) listPreference.getDialog(); ListView listView = listDialog.getListView(); listView.performItemClick(listView, listItemPos, 0); } /*** * Finding a ListPreference is difficult when Preference Categories are involved, * as the category header itself counts as a position in the preferences screen * list. * * This method iterates over the preference items inside preference categories * to find the ListPreference that is wanted. * * @return The position of the ListPreference relative to the entire preferences screen list */ private int getPreferencePosition(){ int counter = 0; PreferenceScreen screen = mActivity.getPreferenceScreen(); // loop over categories for (int i = 0; i < screen.getPreferenceCount(); i++){ PreferenceCategory cat = (PreferenceCategory) screen.getPreference(i); counter++; // loop over category items for (int j = 0; j < cat.getPreferenceCount(); j++){ if (cat.getPreference(j).getKey().contentEquals(listPreferenceKey)){ return counter; } counter++; } } return 0; // did not match } } ); getInstrumentation().waitForIdleSync(); }

A few more hours of work produced this working solution, but I'm curious if anyone else has a better solution. This code was inspired by this solution to a similar question, but this case is different in two ways:

It's intended for use by Android JUnit, which means it needs to call the ListPreference UI clicks via runOnUiThread(). It expects there to be preference categories in use, which complicate finding the position (relative to the entire preferences list) to click. The above mentioned solution only works in cases without preference categories.

This method will accept the key for a particular ListPreference item, along with the position of the item in the list to be clicked. It will then perform that list item click, and other code would do the checking I'm looking for.

Note that this requires setActivityInitialTouchMode(true); to be set before the getActivity() call in the setUp() method.

private void clickListPreference(String _listPreferenceKey, int _listItemPos){ final String listPreferenceKey = _listPreferenceKey; final int listItemPos = _listItemPos; mActivity.runOnUiThread( new Runnable() { public void run() { // get a handle to the particular ListPreference ListPreference listPreference= (ListPreference) mActivity.findPreference(listPreferenceKey); // bring up the dialog box mActivity.getPreferenceScreen().onItemClick( null, null, getPreferencePosition(), 0 ); // click the requested item AlertDialog listDialog = (AlertDialog) listPreference.getDialog(); ListView listView = listDialog.getListView(); listView.performItemClick(listView, listItemPos, 0); } /*** * Finding a ListPreference is difficult when Preference Categories are involved, * as the category header itself counts as a position in the preferences screen * list. * * This method iterates over the preference items inside preference categories * to find the ListPreference that is wanted. * * @return The position of the ListPreference relative to the entire preferences screen list */ private int getPreferencePosition(){ int counter = 0; PreferenceScreen screen = mActivity.getPreferenceScreen(); // loop over categories for (int i = 0; i < screen.getPreferenceCount(); i++){ PreferenceCategory cat = (PreferenceCategory) screen.getPreference(i); counter++; // loop over category items for (int j = 0; j < cat.getPreferenceCount(); j++){ if (cat.getPreference(j).getKey().contentEquals(listPreferenceKey)){ return counter; } counter++; } } return 0; // did not match } } ); getInstrumentation().waitForIdleSync(); }

更多推荐