1

BottomNavigationItemView实现了具有setChecked()方法的ItemView接口。如何断言BottomNavigationItemView是用Espresso检查的?

我试图用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当前选定的项目?

+0

也许在这种情况下尝试使用经典的JUnit断言而不是Espresso断言。我的意思是:'assertEquals(((BottomNavigationItemView)findViewById(R.id.bottomHome))。isChecked(),true);' – piotrek1543

回答

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

尼斯'Matcher'。小的说法,避免使用'BottomNavigationItemView',因为它只对组ID有效。尝试迭代实现'MenuItem'的'bottomNavigationView.getChildAt(0)'的子元素。 –

+0

太神奇了,谢谢。 – oldergod

0

基于上述回答和评论,我创造了这个匹配:

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); 
     } 
    }; 
    } 
} 

可以像这样使用:

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