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.
Related
I have an activity in which I provide a button. Clicking on the button invokes a method in a data provider class and based on the return value of the method I make UI changes. Now I want to write an instrumented test where I perform click() in the button but avoid actually calling the method in the data provider class. Instead I want to return a desired value from the method and then check if the UI was modified accordingly.
MyActivity
#Override
public void onCreate(final Bundle savedInstanceState) {
mActionButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(final View v) {
boolean result = dataProvider.getResult();
if(result) {
mSuccessTextView.setVisibility(View.VISIBLE);
}
}
});
}
Here, on button click, a call is made to DataProvider#getResult and the result from this method is stored in result. If the result is true a TextView mSuccessTextView, previously GONE, is now made VISIBLE.
The problem here is DataProvider#getResult deals with a lot of external components that would make testing impossible. So what I want to do is use a mocked instance of DataProvider so that I can get getResult to return a desired value and then check the visibility of mSuccessTextView. This is what I tried :
MyActivityTest.java
#RunWith(AndroidJUnit4.class)
public class MyActivityTest {
private DataProvider mDataProvider;
#Rule
public IntentsTestRule<MyActivity> mIntentRule =
new IntentsTestRule<>(MyClientActivity.class);
#Before
public void setUp() {
mDataProvider = mock(DataProvider.class);
}
#Test
public void testResultSuccess() {
boolean result = true;
when(mDataProvider.getResult()).thenReturn(result);
onView(withId(R.id.action_button)).perform(click());
onView(withId(R.id.success_text_view)).check((ViewAssertion) isDisplayed());
}
}
Doing the above generates the following error :
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class com.domain.myapp.DataProvider.
Mockito can only mock non-private & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.
Underlying exception : java.lang.UnsupportedOperationException: Cannot define class using reflection
.
.
.
Caused by: java.lang.UnsupportedOperationException: Cannot define class using reflection
.
.
.
Caused by: java.lang.IllegalStateException: This JVM's version string does not seem to be valid: 0
.
.
.
Even if you could mock DataProvider, it would not help you because you are not injecting its instance into MyClientActivity during your test. Reasons for not able to mock DataProvider are unknown, pls provide the class.
I am working on writing the test cases for my application and it worked well for Activities. But when it comes to Fragment inside the ViewPager my cases are failed.
Below test case fails because the fragment shows an empty view if run this directly.
public class SentimentsFragmentEspressoTest {
#Rule
public FragmentTestRule<SentimentsFragment> mFragmentTestRule = new FragmentTestRule<>(SentimentsFragment.class);
#Test
public void fragment_can_be_instantiated() {
// Launch the activity to make the fragment visible
mFragmentTestRule.launchActivity(null);
// Then use Espresso to test the Fragment
onView(withId(R.id.listSentiments))
.perform(RecyclerViewActions.scrollToPosition(4));
}
}
How do I overcome this issue?
I have found the solutions for my above question. Here is the code snippet.
ViewInteraction recyclerView = onView(
allOf(withId(R.id.listSentiments),
withParent(withId(R.id.viewpager)),
isDisplayed()));
recyclerView.perform(actionOnItemAtPosition(3, click()));
From this way you can access all the fragments which is connected with Viewpager.
For Fragment inside the ViewPager try to use in your Test
#Rule
public ActivityTestRule<YourActivity> mActivityRule = new ActivityTestRule<>(YourActivity.class);
#Before
public void setUp() throws Exception {
//get fragment
mActivityRule.getActivity()
.getSupportFragmentManager().beginTransaction();
}
#Test
public void testRecyclerView() {
//click on item recyclerview
onView(withId(R.id.listSentiments)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
....
...
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());
}
}
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
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.