I want to know how to set an item in a spinner in espresso testing.
onView(withId(R.id.spinner_gender)).perform(click());
onData(allOf(is(instanceOf(String.class)))).atPosition(0).perform(click());
This code above does not work :/
Your code snippet looks correct, so there may be an issue with another part of your test class?
Are you getting an Exception or stack-trace you can update your question with? Also check the espresso documentation for a bit more explaination.
See small code example of how you can select a spinner option by text or it's position.
#RunWith(AndroidJUnit4.class)
public class BasicEspressoTest {
#Rule
public ActivityTestRule<MainActivity> testRule = new ActivityTestRule<>(MainActivity.class);
#Test
public void selectBySpinnerPosition() throws Exception {
onView(withId(R.id.spinner)).perform(click());
onData(allOf(is(instanceOf(String.class)))).atPosition(0).perform(click());
}
#Test
public void selectBySpinnerText() throws Exception {
onView(withId(R.id.spinner)).perform(click());
onData(allOf(is(instanceOf(String.class)), is("spinner's text"))).perform(click());
}
}
Related
I wrote an Espresso test that writes some text to a TextView, performs an action and then checks whether the text in the TextView is still the same.
The test fails on one of the test devices (Huawei P20, Android 8.1.0) because the entered text is auto-corrected (from 1234 5678 to 12th 5678). And this fails my test. The text is not auto-corrected when I manually enter the same numbers.
This is how I input the text in my Espresso test:
onView(withId(R.id.reference_value))
.perform(scrollTo(), click())
.check(matches(isDisplayed()))
.perform(typeText("1234 5678"));
closeSoftKeyboard();
I know I could just change the input text to something that won't be auto-corrected. But I would like to have a solution that generally makes sure that the entered text is not modified to something else. Ideally without having to manually change the configuration of my test device.
Do any of you guys have an idea how I could accomplish this?
One way that works for me is to use replaceText() instead, although this still seems to be a bit of a hack.
Another option may be to disable autocorrect through some Android API call or manually through the UI like for animations.
This issue occurs with some keyboards. For me it was with Microsoft SwiftKey Keyboard was set as my default keyboard.
Two solutions that worked for me:
Solution 1: Change input type to TYPE_TEXT_FLAG_NO_SUGGESTIONS during test if using typeText which disables the suggestions & corrections for that view.
Example:
#RunWith(AndroidJUnit4.class)
#LargeTest
public class HelloWorldEspressoTest {
#Rule
public ActivityScenarioRule<MainActivity> activityScenarioRule
= new ActivityScenarioRule<>(MainActivity.class);
#Before
public void setUp() {
// get the view & set the input type
activityScenarioRule.getScenario().onActivity(activity ->
((EditText) activity.findViewById(R.id.etHello))
.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS));
}
#Test
public void testText() {
onView(withId(R.id.etHello)).perform(typeText("Smoth go"));
onView((withId(R.id.etHello))).check(matches(withText("Smoth go")));
}
}
Solution 2: Using my own ViewAction
Helper.java -> This file is placed inside the same test package with test.
public class Helper {
public static ViewAction setTextInEt(final String value){
return new ViewAction() {
#Override
public Matcher<View> getConstraints() {
return allOf(isDisplayed(), isAssignableFrom(EditText.class));
}
#Override
public void perform(UiController uiController, View view) {
((EditText) view).setText(value);
}
#Override
public String getDescription() {
return "set text";
}
};
}
}
Test class:
#RunWith(AndroidJUnit4.class)
#LargeTest
public class HelloWorldEspressoTest {
#Rule
public ActivityScenarioRule<MainActivity> activityScenarioRule
= new ActivityScenarioRule<>(MainActivity.class);
#Test
public void testText() {
onView(withId(R.id.etHello)).perform(Helper.setTextInEt("Smoth go"));
onView((withId(R.id.etHello))).check(matches(withText("Smoth go")));
}
}
So far solution 2 has worked very well for me. Before that smoth text was auto-corrected to smooth every time.
This can be done for the TextView as well just replace EditText to TextView in helper method.
I need to write a UI test to validate that clicking the floating action button results in displaying the SecondActivity.
public class MainActivityTest {
#Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
MainActivity.class);
#Before
public void setUp() throws Exception {
}
#Test
public void onClick() throws Exception {
onView(withId(R.id.button)).perform(click());
}
}
Is it enough?
And how can I validate that the Activity properly displays the text contents of an incoming object: name, age, phone number?
I have just started using espresso(
Is it enough?
No, it is not enough. This code
onView(withId(R.id.button)).perform(click()); only performs a click on the button, but there is nothing that verifies that the application behaved correctly after that.
To verify that an intent to open the SecondActivity was created, you need to use Espresso Intents.
how can I validate that the Activity properly displays the text contents of an incoming object
You can use something like:
onView(withId(R.id.textView)).check(matches(withText("Expected text")));
Take a look at the Espresso Cheatsheet for more.
JUnit library has an Assume.* instructions like Assume.assumeTrue(boolean) which works like assertions, but not cause test to fail and just to been ignored.
I want to perform such checking in arrange part of test for one of my views, by example assume, that founded checkbox is checked before starting the act part of test.
Take a look:
#Rule
public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);
#Test
public void deselectFilter_AllFiltersSelected_CheckboxAllSelectedUnchecked() {
//arrange
ViewInteraction checkBox = onView(
allOf(withId(R.id.cbCheckAll), isDisplayed()));
//assume that this checkbox is checked
//act
...
//assert
...
}
In the arrange part i've received not a View, but ViewInteraction.
So I can perform such assertion like checkBox.check(matches(isChecked()))
But how to perform assume?
You could write a custom ViewAssertion to assume that no Exception is thrown when Espresso ViewMatcher fails:
public static ViewAssertion assume(final Matcher<? super View> viewMatcher) {
return new ViewAssertion() {
#Override
public void check(final View view, final NoMatchingViewException noViewFoundException) {
try {
ViewAssertions.matches(viewMatcher).check(view, noViewFoundException);
} catch (Throwable e) {
// Assume that there is no exception
Assume.assumeNoException(e);
}
}
};
}
Then you can use that assertion to assume like:
onView(withId(R.id.cbCheckAll)).check(assume(isChecked()));
The only way i've founded at this moment is just finding assuming view manually with activity from test rule. And then assume via jUnit.
CheckBox checkBox = (CheckBox) mActivityTestRule.getActivity().findViewById(R.id.cbCheckAll);
Assume.assumeTrue(checkBox.isChecked());
If you know a better way, maybe with using Espresso, please answer. Seems that it impossible to access view directly from Espresso commands
for example here is my code:
#Test
public void manga_list2() throws Exception {
onView(withId(R.id.manga_list));
}
I try onView(withId(R.id.manga_list)) result is ViewInteration, I hope get finded View and I try onView(withId(R.id.manga_list)).viewFinder.getView() in android studio > watches tool, and i get error:
Executing a query on the view hierarchy outside of the main thread (on: Instr: android.support.test.runner.AndroidJUnitRunner)
how to get the view?
update
if it cannot, please recommend me other ui testing that can get view directly, the espresso is too black-box
"espresso is too black-box" - exactly the opposite. Below is the code you can use to get the whatever view from your activity. In the example I'm getting the ListView:
#RunWith(AndroidJUnit4.class)
#LargeTest
public class EspressoTest {
#Rule
public ActivityTestRule<YourTestActivity> mActivityRule =
new ActivityTestRule<>(YourTestActivity.class);
#Test
public void doSomeStuff() {
ListView listView = (ListView)mActivityRule.getActivity().findViewById(R.id.manga_list);
}
}
More examples here - android-testing-templates.
I have a simple test today:
#RunWith(AndroidJUnit4.class)
#LargeTest
public class WhenNavigatingToUsersView {
#Rule
public ActivityTestRule<MainActivity> mActivityRule =
new ActivityTestRule(MainActivity.class);
private MainActivity mainActivity;
#Before
public void setActivity() {
mainActivity = mActivityRule.getActivity();
onView(allOf(withId(R.id.icon), hasSibling(withText(R.string.users)))).perform(click());
}
#Test
public void thenCorrectViewTitleShouldBeShown() {
onView(withText("This is the Users Activity.")).check(matches(isDisplayed()));
}
#Test
public void thenCorrectUserShouldBeShown() {
onView(withText("Donald Duck (1331)")).check(matches(isDisplayed()));
}
}
But for every test method the setActivity is run, which, if you have 10-15 methods, in the end will be time consuming (if you have a lot of views too).
#BeforeClass doesn't seem to work since it has to be static and thus forcing the ActivityTestRule to be static as well.
So is there any other way to do this? Rather than having multiple asserts in the same test method?
#Before annotation should only precede methods containing preliminary setup. Initialization of needed objects, getting the current session or the current activity, you get the idea.
It is replacing the old setUp() method from the ActivityInstrumentationTestCase2, just as #After replaces the tearDown().
That means that it is intended to be executed before every test in the class and it should stay that way.
You should have no ViewInteraction, no DataInteraction, no Assertions nor View actions in this method, since that is not its purpose.
In your case, simply remove the onView() call from setActivity() and put it inside the actual test methods, in every test method if necessary, like so:
#RunWith(AndroidJUnit4.class)
#LargeTest
public class WhenNavigatingToUsersView {
#Rule
public ActivityTestRule<MainActivity> mActivityRule =
new ActivityTestRule(MainActivity.class);
private MainActivity mainActivity;
#Before
public void setActivity() {
mainActivity = mActivityRule.getActivity();
// other required initializations / definitions
}
#Test
public void thenCorrectViewTitleShouldBeShown() {
onView(allOf(withId(R.id.icon), hasSibling(withText(R.string.users)))).perform(click());
onView(withText("This is the Users Activity.")).check(matches(isDisplayed()));
}
#Test
public void thenCorrectUserShouldBeShown() {
onView(allOf(withId(R.id.icon), hasSibling(withText(R.string.users)))).perform(click());
onView(withText("Donald Duck (1331)")).check(matches(isDisplayed()));
}
}
Another option for you would be separating these tests.
Clicking on the user's icon will be in the HomeActivity test class while the rest of the tests will be in the UserActivity test class.
UserActivity test class will launch UserActivity with the proper Intent ( you can do so by passing the false Boolean into the Rule constructor and calling launchActivity(intent) manually).
This will eliminate the necessity of setting up the activity every single time. It will also get rid of constant dependency on the main activity. If something goes wrong, your UserActivity tests will be intact and will produce the results, while the issue will be caught by the test in the MainActivity.
Actually, by doing so your tests will might become MediumSize as the runtime will drastically decrease.
You can try this :
**** Setting ****
public void testStory() throws Exception {
}
public void testStory2() throws Exception {
}
public void testStory3() throws Exception {
}
Try to run your test by this command:
./gradlew cC
Did you try doing it as follows or a minor variation of it to suit your needs:
#Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule(MainActivity.class);
private MainActivity mainActivity = mActivityRule.getActivity();
#BeforeClass
public static void setActivity() {
onView(allOf(withId(R.id.icon), hasSibling(withText(R.string.users)))).perform(click());
}
This way, you 'mainActivity' need not be static. Also, the setActivity() method will get called only once.