タイトルの通り、オプションメニューにあるcheckableなMenuItemのテストをしたくて、こんな投稿をしました。
が、回答が付かず・・・
まあ英語で使ってなんぼですよね、Stack Overflowは。
で、結局いろいろ試行錯誤して、質問にも載せたViewの階層状態を参考にして、次のようにMatcherを作りました。
Matcherを作るのには全然馴れていないので、かなり四苦八苦しましたが、見た感じ意図したとおりに動作しているようです。
やっていることは、Checkboxクラスのオブジェクトを全部受け取って、その親Viewが持つ子Viewの中からTextViewを探して、そいつが指定したタイトル文字列を持っているかチェックしています。
階層状態が見えたから書けた愚直な手法ですね。
OSのバージョンが違ったらもしかしたらアウトかも知れませんが、support-libraryを使っている間は大丈夫な気がします・・・が、何も保証は出来ません。
EspressoUtil.java
public static MenuItemTitleMatcher withCheckBoxTitle(final String title) {
return new MenuItemTitleMatcher(title);
}
public static class MenuItemTitleMatcher extends BaseMatcher<Object> {
private final String title;
public MenuItemTitleMatcher(String title) {
this.title = title;
}
TextView getChildTextView(ViewGroup view, String title) {
int num = view.getChildCount();
for (int i = 0; i < num; i++) {
View child = view.getChildAt(i);
if (child instanceof TextView) {
if (title.equals(((TextView) child).getText())) {
return (TextView) child;
}
}
}
return null;
}
@Override
public boolean matches(Object o) {
if (o instanceof CheckBox) {
CheckBox checkbox = (CheckBox) o;
ViewParent parent = checkbox.getParent();
if (parent instanceof ListMenuItemView) {
// 子のViewGroupからTextViewを探す
int num = ((ListMenuItemView) parent).getChildCount();
for (int i = 0; i < num; i++) {
View child = ((ListMenuItemView) parent).getChildAt(i);
if (child == o) continue;
if (child instanceof ViewGroup) {
TextView textView = getChildTextView((ViewGroup) child, title);
if (textView != null)
return true;
}
}
}
return false;
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText("expected with Title: ");
description.appendText("" + title);
}
}
使い方
onView(allOf(withClassName(endsWith("CheckBox")),
EspressoUtil.withCheckBoxTitle(getString(R.string.action_lock))))
.check(matches(isNotChecked()))
.perform(click());