8

Ich versuche, mit Espresso zu testen, wenn meine TextInputLayout Ansichten einen spezifischen Hinweis haben.Testen von TextInputLayout-Werten (Hinweis, Fehler usw.) mit Android Espresso?

Espresso.onView(ViewMatchers.withId(R.id.edit_text_email)) 
    .check(ViewAssertions.matches(
     ViewMatchers.withHint(R.string.edit_text_email_hint))) 

Dies funktioniert gut für die normalen EditText Ansichten, nicht eingewickelt in TextInputLayout: Ich hatte einen Code wie unten verwendet. Wenn es jedoch umgebrochen wird, funktioniert es nicht mehr.

Ich habe versucht, Lösung von Android Espresso - How to check EditText hint? zu verwenden, aber es funktioniert immer noch nicht.

Ich schaute auch in: https://code.google.com/p/android/issues/detail?id=191261, die das Problem gemeldet, es heißt, die Problemumgehung ist ziemlich einfach durch Hinweis auf die aktuelle withHint-Code, aber ich kann es nicht zur Arbeit bekommen.

Irgendwelche Ideen, um dieses Problem zu beheben?

Antwort

16

Hier ist meine Gewohnheit Matcher:

public static Matcher<View> hasTextInputLayoutHintText(final String expectedErrorText) { 
     return new TypeSafeMatcher<View>() { 

      @Override 
      public boolean matchesSafely(View view) { 
       if (!(view instanceof TextInputLayout)) { 
        return false; 
       } 

       CharSequence error = ((TextInputLayout) view).getHint(); 

       if (error == null) { 
        return false; 
       } 

       String hint = error.toString(); 

       return expectedErrorText.equals(hint); 
      } 

      @Override 
      public void describeTo(Description description) { 
      } 
     }; 
    } 
} 

und hier ist, wie man verwendet:

@RunWith(AndroidJUnit4.class) 
public class MainActivityTest { 

    @Rule 
    public ActivityTestRule<MainActivity> mRule = new ActivityTestRule<>(MainActivity.class); 

    @Test 
    public void testMyApp() { 
     onView(withId(R.id.textInputLayout)).check 
       (matches(hasTextInputLayoutErrorText(mRule.getActivity().getString(R.string 
         .app_name)))); 

    } 

Wenn Sie möchten, errorText von TextInputLayout überprüfen, ändern Sie diese Zeile:

 CharSequence error = ((TextInputLayout) view).getHint(); 

mit

 CharSequence error = ((TextInputLayout) view).getError(); 

Hoffe, dass es

+0

Dies funktioniert. Ich danke dir sehr! – Elye

+0

Wo kann ich benutzerdefinierte Matcher hasTextInputLayoutHintText setzen? – aleksandrbel

+0

Da ich in meinem Code den Fehler auf TextInputEditText gesetzt habe, musste ich TextInputLayout in TextInputEditText im Matcher ändern. –

1

Weitere generische Lösung helfen wird, die mit jeder Ansicht, die "GETHINT" Methode hat funktionieren würde:

public static Matcher<View> withCustomHint(final Matcher<String> stringMatcher) { 
    return new BaseMatcher<View>() { 
     @Override 
     public void describeTo(Description description) { 
     } 

     @Override 
     public boolean matches(Object item) { 
      try { 
       Method method = item.getClass().getMethod("getHint"); 
       return stringMatcher.matches(method.invoke(item)); 
      } catch (NoSuchMethodException e) { 
      } catch (InvocationTargetException e) { 
      } catch (IllegalAccessException e) { 
      } 
      return false; 
     } 
    }; 
} 

Verbrauch:

onView(withId(R.id.SomeLayout)).check(matches(withCustomHint(is("SomeString")))); 
0

Die Lösungen oben didn‘ t arbeite für meinen Anwendungsfall. Ich wollte den TextInputEditText finden und Text eingeben. Hier ist meine Lösung:

@VisibleForTesting 
class WithTextInputLayoutHintMatcher @RemoteMsgConstructor 
constructor(@field:RemoteMsgField(order = 0) 
      private val stringMatcher: Matcher<String>) : TypeSafeMatcher<View>() { 

    override fun describeTo(description: Description) { 
     description.appendText("with TextInputLayout hint: ") 
     stringMatcher.describeTo(description) 
    } 

    public override fun matchesSafely(textInputEditText: View): Boolean { 
     if (textInputEditText !is TextInputEditText) return false 

     return stringMatcher.matches((textInputEditText.parent.parent as? TextInputLayout)?.hint) 
    } 
} 

/** 
* Returns a matcher that matches [TextInputEditText] based on it's hint property value. 
* 
* 
* **Note:** View's sugar for `withHint(is("string"))`. 
* 
* @param hintText [String] with the hint text to match 
*/ 
fun withTextInputHint(hintText: String): Matcher<View> { 
    return withTextInputHint(Matchers.`is`(checkNotNull(hintText))) 
} 

/** 
* Returns a matcher that matches a descendant of [TextInputEditText] that is displaying the hint 
* associated with the given resource id. 
* 
* @param resourceId the string resource the text view is expected to have as a hint. 
*/ 
fun withTextInputHint(resourceId: Int): Matcher<View> { 
    return withTextInputHint(getString(resourceId)) 
} 

/** 
* Returns a matcher that matches [TextView]s based on hint property value. 
* 
* 
* **Note:** View's hint property can be `null`, to match against it use ` 
* withHint(nullValue(String.class)` 
* 
* @param stringMatcher [`Matcher 
`](http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html) * of [String] with text to match 
*/ 
fun withTextInputHint(stringMatcher: Matcher<String>): Matcher<View> { 
    return WithTextInputLayoutHintMatcher(checkNotNull(stringMatcher)) 
} 

Verbrauch:

onView(withTextInputHint(R.string.hint)).perform(ViewActions.typeText("Type text here"))