如何断言使用Espresso检查BottomNavigationItemView?

时间:2016-10-22 12:09:09

标签: android android-espresso android-testing bottomnavigationview

BottomNavigationItemView实现了具有ItemView方法的setChecked()接口。

我试图用Espresso断言我检查了一个itemView但是我得到了同样的错误,无论我的期望值是什么,isChecked()还是isNotChecked()

我的测试:

ViewInteraction buttonHome = onView(
    allOf(withId(R.id.bottomHome),
          childAtPosition(
              childAtPosition(
                  withId(R.id.bottom_navigation),
                  0),
              0),
          isDisplayed()));
    buttonHome.check(matches(isNotChecked()));

错误消息

android.support.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: 'with checkbox state: is <true>' doesn't match the selected view.
Expected: with checkbox state: is <true>
Got: "BottomNavigationItemView{id=2131493015, res-name=bottomHome, visibility=VISIBLE, width=360, height=168, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}"

如何断言BottomNavigationItemViewBottomNavigationView的当前所选项?

2 个答案:

答案 0 :(得分:3)

isChecked()isNotChecked()期望Checkable接口由视图实现。

此外,BottomNavigationItemView会在itemData字段内隐藏其已检查状态。这意味着开箱即用的Espresso不支持这种检查。幸运的是,Espresso是一个非常易扩展的框架,您可以轻松地为其添加功能。在这种情况下,我们需要编写一个自定义匹配器来进行检查。

所述匹配器的实现可能如下所示:

public static Matcher<View> withBottomNavItemCheckedStatus(final boolean isChecked) {
    return new BoundedMatcher<View, BottomNavigationItemView>(BottomNavigationItemView.class) {
        boolean triedMatching;

        @Override
        public void describeTo(Description description) {
            if (triedMatching) {
                description.appendText("with BottomNavigationItem check status: " + String.valueOf(isChecked));
                description.appendText("But was: " + String.valueOf(!isChecked));
            }
        }

        @Override
        protected boolean matchesSafely(BottomNavigationItemView item) {
            triedMatching = true;
            return item.getItemData().isChecked() == isChecked;
        }
    };
}

用法是:

buttonHome.check(matches(withBottomNavItemCheckedStatus(false)));

答案 1 :(得分:1)

Based on the above answer and comments, I created this matcher:

import android.support.design.widget.BottomNavigationView;
import android.support.test.espresso.matcher.BoundedMatcher;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import java.util.HashSet;
import java.util.Set;
import org.hamcrest.Description;
import org.hamcrest.Matcher;

/**
 * Custom matchers for Espresso.
 */
public class EspressoUtils {
  /**
   * Checks that {@link BottomNavigationView} contains an item with provided id and that it is
   * checked.
   *
   * @param id of the item to find in the navigation view
   * @return a matcher that returns true if the item was found and checked
   */
  public static Matcher<View> hasCheckedItem(final int id) {
    return new BoundedMatcher<View, BottomNavigationView>(BottomNavigationView.class) {
      Set<Integer> checkedIds = new HashSet<>();
      boolean itemFound = false;
      boolean triedMatching = false;

      @Override public void describeTo(Description description) {
        if (!triedMatching) {
          description.appendText("BottomNavigationView");
          return;
        }

        description.appendText("BottomNavigationView to have a checked item with id=");
        description.appendValue(id);
        if (itemFound) {
          description.appendText(", but selection was=");
          description.appendValue(checkedIds);
        } else {
          description.appendText(", but it doesn't have an item with such id");
        }
      }

      @Override protected boolean matchesSafely(BottomNavigationView navigationView) {
        triedMatching = true;

        final Menu menu = navigationView.getMenu();
        for (int i = 0; i < menu.size(); i++) {
          final MenuItem item = menu.getItem(i);
          if (item.isChecked()) {
            checkedIds.add(item.getItemId());
          }
          if (item.getItemId() == id) {
            itemFound = true;
          }
        }
        return checkedIds.contains(id);
      }
    };
  }
}

That can be used like:

  @Test public void verifyWalletIsSelected() throws Exception {
    onView(withId(R.id.navigation)).check(matches(hasCheckedItem(R.id.navigation_wallet)));
  }