问题
We currently have an Android application that we are testing with Espresso. One of the features we want to test is selecting a picture/image from the local image gallery. We can get all the way to bringing up the Gallery view, but then cannot select from Recent, Downloads, Gallery in the resulting window. A snippet as to how we got as far as we did is included below.
public void testShouldBeAbleToSelectPhotoFromGallery() {
getActivity();
// given
onView(withId(launch_gallery_button)).perform(click());
onView(withText("Gallery")).perform(click()); // this is a button in our app
// then we get stuck :(
}
Thanks!
回答1:
This is not possible with with either Robotium or Espresso, as they only work on Activities of the app under test.
To write integration tests that work across different apps and Android built-in apps, you can use the UiAutomator framework provided by Google.
Basically you would analyse the gallery app in the uiautomatorview to learn how to select the ui elements your test case needs and then act on them, not unlike Espresso.
回答2:
If you want to test that functionality in your app you should use the intent mocking functionality in Espresso. Espresso tests should not leave your app in the first place. Instead you catch the intent you use to open the gallery app and return a result back to your app. During the test you will stay in your app, you will get a result immediately.
To do this check the intending
and intended
api's of Espresso.
Here is a tutorial by Pengj to get you acquainted with intent mocking. The tutorial mentions Mockito but you can perfectly use this without it.
回答3:
The best and proper way is to use Espresso Intents. So you need to add the dependency in your app's build.gradle
androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
In my case I was openning the gallery from a button within my app, then the code for the test and the addition of the intending and intended api's of Espresso as follows:
@Test
fun photos_CreationGalleryClickUI() {
savePickedImage()
val imgGalleryResult = createImageGallerySetResultStub()
intending(hasAction(Intent.ACTION_CHOOSER)).respondWith(imgGalleryResult)
onView(withId(R.id.photos_button_gallery)).perform(click())
onView(withId(R.id.photos_bigimage_viewer)).check(matches(hasImageSet()))
}
Here the matcher for intending is the key when the gallery needs to be open and avoid to manually pick an image:
hasAction(Intent.ACTION_CHOOSER)
I' using two helpers: savePickedImage() to mock an image from the gallery
private fun savePickedImage() {
val bm = BitmapFactory.decodeResource(mActivityTestRule.activity.resources, R.mipmap.ic_launcher)
assertTrue(bm != null)
val dir = mActivityTestRule.activity.externalCacheDir
val file = File(dir?.path, "myImageResult.jpeg")
System.out.println(file.absolutePath)
val outStream: FileOutputStream?
try {
outStream = FileOutputStream(file)
bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream)
outStream.flush()
outStream.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
And createImageGallerySetResultStub to stubbing the result after "picking" the image. Here putting the result as an array of parcelables was key, without it, the never result was never recognized:
private fun createImageGallerySetResultStub(): Instrumentation.ActivityResult {
val bundle = Bundle()
val parcels = ArrayList<Parcelable>()
val resultData = Intent()
val dir = mActivityTestRule.activity.externalCacheDir
val file = File(dir?.path, "myImageResult.jpeg")
val uri = Uri.fromFile(file)
val myParcelable = uri as Parcelable
parcels.add(myParcelable)
bundle.putParcelableArrayList(Intent.EXTRA_STREAM, parcels)
resultData.putExtras(bundle)
return Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)
}
hasImageSet() as a matcher helper that checks if the imageView has or not a drawable:
return item.getDrawable() == null
NOTE: Remember to set the grant rule to avoid problems with the permissions and to define your test rule as an IntentTestRule (which extends from ActivityTestRule already)
@get:Rule
var mActivityTestRule = IntentsTestRule(AuctionCreationActivity::class.java)
@get:Rule var mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
The dependency:
androidTestImplementation "androidx.test:rules:$testRules"
来源:https://stackoverflow.com/questions/26469661/how-to-click-on-android-gallery-with-espresso