Framework Pengujian Espresso - Maksud
Android Intent digunakan untuk membuka aktivitas baru, baik internal (membuka layar detail produk dari layar daftar produk) atau eksternal (seperti membuka dialer untuk melakukan panggilan). Aktivitas maksud internal ditangani secara transparan oleh framework pengujian espresso dan tidak memerlukan pekerjaan khusus dari sisi pengguna. Namun, menjalankan aktivitas eksternal benar-benar sebuah tantangan karena berada di luar cakupan kami, aplikasi yang sedang diuji. Setelah pengguna memanggil aplikasi eksternal dan keluar dari aplikasi yang sedang diuji, maka kemungkinan pengguna kembali ke aplikasi dengan urutan tindakan yang telah ditentukan menjadi lebih kecil. Oleh karena itu, kita perlu mengasumsikan tindakan pengguna sebelum menguji aplikasi. Espresso menyediakan dua opsi untuk menangani situasi ini. Mereka adalah sebagai berikut,
dimaksudkan
Ini memungkinkan pengguna untuk memastikan maksud yang benar dibuka dari aplikasi yang diuji.
berniat
Hal ini memungkinkan pengguna untuk mengejek aktivitas eksternal seperti mengambil foto dari kamera, memanggil nomor dari daftar kontak, dll., Dan kembali ke aplikasi dengan nilai yang telah ditentukan sebelumnya (seperti gambar yang telah ditentukan dari kamera, bukan gambar sebenarnya) .
Mendirikan
Espresso mendukung opsi maksud melalui pustaka plugin dan pustaka tersebut perlu dikonfigurasi dalam file gradle aplikasi. Opsi konfigurasinya adalah sebagai berikut,
dependencies {
// ...
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.1'
}
dimaksudkan ()
Plugin maksud Espresso menyediakan pencocokan khusus untuk memeriksa apakah maksud yang dipanggil adalah maksud yang diharapkan. Matcher yang disediakan dan tujuan dari matcher adalah sebagai berikut,
hasAction
Ini menerima tindakan maksud dan mengembalikan matcher, yang cocok dengan maksud yang ditentukan.
hasData
Ini menerima data dan mengembalikan matcher, yang mencocokkan data yang diberikan ke maksud saat menjalankannya.
toPackage
Ini menerima nama paket maksud dan mengembalikan matcher, yang cocok dengan nama paket maksud yang dipanggil.
Sekarang, mari kita membuat aplikasi baru dan menguji aplikasi untuk aktivitas eksternal menggunakan intended () untuk memahami konsepnya.
Mulai studio Android.
Buat proyek baru seperti yang dibahas sebelumnya dan beri nama, IntentSampleApp.
Migrasikan aplikasi ke framework AndroidX menggunakan Refactor → Migrate to AndroidX option menu.
Buat kotak teks, tombol untuk membuka daftar kontak dan satu lagi untuk melakukan panggilan dengan mengubah activity_main.xml seperti yang ditunjukkan di bawah ini,
<?xml version = "1.0" encoding = "utf-8"?>
<RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:app = "http://schemas.android.com/apk/res-auto"
xmlns:tools = "http://schemas.android.com/tools"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:context = ".MainActivity">
<EditText
android:id = "@+id/edit_text_phone_number"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_centerHorizontal = "true"
android:text = ""
android:autofillHints = "@string/phone_number"/>
<Button
android:id = "@+id/call_contact_button"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_centerHorizontal = "true"
android:layout_below = "@id/edit_text_phone_number"
android:text = "@string/call_contact"/>
<Button
android:id = "@+id/button"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_centerHorizontal = "true"
android:layout_below = "@id/call_contact_button"
android:text = "@string/call"/>
</RelativeLayout>
Juga, tambahkan item di bawah ini dalam file sumber daya strings.xml ,
<string name = "phone_number">Phone number</string>
<string name = "call">Call</string>
<string name = "call_contact">Select from contact list</string>
Sekarang, tambahkan kode di bawah ini di aktivitas utama ( MainActivity.java ) di bawah metode onCreate .
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// ... code
// Find call from contact button
Button contactButton = (Button) findViewById(R.id.call_contact_button);
contactButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Uri uri = Uri.parse("content://contacts");
Intent contactIntent = new Intent(Intent.ACTION_PICK,
ContactsContract.Contacts.CONTENT_URI);
contactIntent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
startActivityForResult(contactIntent, REQUEST_CODE);
}
});
// Find edit view
final EditText phoneNumberEditView = (EditText)
findViewById(R.id.edit_text_phone_number);
// Find call button
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(phoneNumberEditView.getText() != null) {
Uri number = Uri.parse("tel:" + phoneNumberEditView.getText());
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
startActivity(callIntent);
}
}
});
}
// ... code
}
Di sini, kami telah memprogram tombol dengan id, call_contact_button untuk membuka daftar kontak dan tombol dengan id, tombol untuk melakukan panggilan.
Tambahkan variabel statis REQUEST_CODE di kelas MainActivity seperti yang ditunjukkan di bawah ini,
public class MainActivity extends AppCompatActivity {
// ...
private static final int REQUEST_CODE = 1;
// ...
}
Sekarang, tambahkan metode onActivityResult di kelas MainActivity seperti di bawah ini,
public class MainActivity extends AppCompatActivity {
// ...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// Bundle extras = data.getExtras();
// String phoneNumber = extras.get("data").toString();
Uri uri = data.getData();
Log.e("ACT_RES", uri.toString());
String[] projection = {
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME };
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
cursor.moveToFirst();
int numberColumnIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
String number = cursor.getString(numberColumnIndex);
int nameColumnIndex = cursor.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
String name = cursor.getString(nameColumnIndex);
Log.d("MAIN_ACTIVITY", "Selected number : " + number +" , name : "+name);
// Find edit view
final EditText phoneNumberEditView = (EditText)
findViewById(R.id.edit_text_phone_number);
phoneNumberEditView.setText(number);
}
}
};
// ...
}
Di sini, onActivityResult akan dipanggil saat pengguna kembali ke aplikasi setelah membuka daftar kontak menggunakan tombol call_contact_button dan memilih kontak. Setelah metode onActivityResult dipanggil, ia mendapatkan kontak yang dipilih pengguna, menemukan nomor kontak dan mengaturnya ke dalam kotak teks.
Jalankan aplikasinya dan pastikan semuanya baik-baik saja. Tampilan akhir dari Contoh Aplikasi Intent adalah seperti yang ditunjukkan di bawah ini,
Sekarang, konfigurasikan maksud espresso dalam file gradle aplikasi seperti yang ditunjukkan di bawah ini,
dependencies {
// ...
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.1'
}
Klik opsi menu Sync Now yang disediakan oleh Android Studio. Ini akan mengunduh pustaka pengujian maksud dan mengonfigurasinya dengan benar.
Buka file ExampleInstrumentedTest.java dan tambahkan IntentsTestRule sebagai ganti AndroidTestRule yang biasanya digunakan . IntentTestRule adalah aturan khusus untuk menangani pengujian maksud.
public class ExampleInstrumentedTest {
// ... code
@Rule
public IntentsTestRule<MainActivity> mActivityRule =
new IntentsTestRule<>(MainActivity.class);
// ... code
}
Tambahkan dua variabel lokal untuk mengatur nomor telepon uji dan nama paket dialer seperti di bawah ini,
public class ExampleInstrumentedTest {
// ... code
private static final String PHONE_NUMBER = "1 234-567-890";
private static final String DIALER_PACKAGE_NAME = "com.google.android.dialer";
// ... code
}
Perbaiki masalah impor dengan menggunakan opsi Alt + Enter yang disediakan oleh android studio atau sertakan pernyataan impor di bawah ini,
import android.content.Context;
import android.content.Intent;
import androidx.test.InstrumentationRegistry;
import androidx.test.espresso.intent.rule.IntentsTestRule;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.action.ViewActions.typeText;
import static androidx.test.espresso.intent.Intents.intended;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasData;
import static androidx.test.espresso.intent.matcher.IntentMatchers.toPackage;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static org.hamcrest.core.AllOf.allOf;
import static org.junit.Assert.*;
Tambahkan kasus uji di bawah ini untuk menguji apakah dialer dipanggil dengan benar,
public class ExampleInstrumentedTest {
// ... code
@Test
public void validateIntentTest() {
onView(withId(R.id.edit_text_phone_number))
.perform(typeText(PHONE_NUMBER), closeSoftKeyboard());
onView(withId(R.id.button)) .perform(click());
intended(allOf(
hasAction(Intent.ACTION_DIAL),
hasData("tel:" + PHONE_NUMBER),
toPackage(DIALER_PACKAGE_NAME)));
}
// ... code
}
Di sini, hasAction , hasData dan toPackage matchers digunakan bersama dengan allof matcher untuk berhasil hanya jika semua matchers berlalu.
Sekarang, jalankan ExampleInstrumentedTest melalui menu konten di Android studio.
berniat ()
Espresso menyediakan metode khusus - intending () untuk meniru tindakan maksud eksternal. intending () menerima nama paket dari maksud yang akan diejek dan menyediakan metode respondWith untuk menyetel bagaimana maksud yang dibuat- buat perlu ditanggapi seperti yang ditentukan di bawah ini,
intending(toPackage("com.android.contacts")).respondWith(result);
Di sini, respondWith () menerima hasil maksud dari tipe Instrumentation.ActivityResult . Kita bisa membuat maksud rintisan baru dan secara manual mengatur hasilnya seperti yang ditentukan di bawah ini,
// Stub intent
Intent intent = new Intent();
intent.setData(Uri.parse("content://com.android.contacts/data/1"));
Instrumentation.ActivityResult result =
new Instrumentation.ActivityResult(Activity.RESULT_OK, intent);
Kode lengkap untuk menguji apakah aplikasi kontak dibuka dengan benar adalah sebagai berikut,
@Test
public void stubIntentTest() {
// Stub intent
Intent intent = new Intent();
intent.setData(Uri.parse("content://com.android.contacts/data/1"));
Instrumentation.ActivityResult result =
new Instrumentation.ActivityResult(Activity.RESULT_OK, intent);
intending(toPackage("com.android.contacts")).respondWith(result);
// find the button and perform click action
onView(withId(R.id.call_contact_button)).perform(click());
// get context
Context targetContext2 = InstrumentationRegistry.getInstrumentation().getTargetContext();
// get phone number
String[] projection = { ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME };
Cursor cursor =
targetContext2.getContentResolver().query(Uri.parse("content://com.android.cont
acts/data/1"), projection, null, null, null);
cursor.moveToFirst();
int numberColumnIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
String number = cursor.getString(numberColumnIndex);
// now, check the data
onView(withId(R.id.edit_text_phone_number))
.check(matches(withText(number)));
}
Di sini, kita telah membuat maksud baru dan menyetel nilai yang dikembalikan (saat memanggil maksud) sebagai entri pertama dari daftar kontak, content: //com.android.contacts/data/1 . Kemudian kami telah menyetel metode maksud untuk mengejek maksud yang baru dibuat di tempat daftar kontak. Ini menetapkan dan memanggil maksud yang baru kita buat ketika paket, com.android.contacts dipanggil dan entri pertama default dari daftar dikembalikan. Kemudian, kami mengaktifkan tindakan click () untuk memulai maksud tiruan dan terakhir memeriksa apakah nomor telepon dari pemanggilan maksud tiruan dan nomor entri pertama dalam daftar kontak adalah sama.
Jika ada masalah impor yang hilang, perbaiki masalah impor tersebut dengan menggunakan opsi Alt + Enter yang disediakan oleh android studio atau sertakan pernyataan impor di bawah ini,
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import androidx.test.InstrumentationRegistry;
import androidx.test.espresso.ViewInteraction;
import androidx.test.espresso.intent.rule.IntentsTestRule;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.action.ViewActions.typeText;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.intent.Intents.intended;
import static androidx.test.espresso.intent.Intents.intending;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasData;
import static androidx.test.espresso.intent.matcher.IntentMatchers.toPackage;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.core.AllOf.allOf;
import static org.junit.Assert.*;
Tambahkan aturan di bawah ini di kelas pengujian untuk memberikan izin untuk membaca daftar kontak -
@Rule
public GrantPermissionRule permissionRule =
GrantPermissionRule.grant(Manifest.permission.READ_CONTACTS);
Tambahkan opsi di bawah ini dalam file manifes aplikasi, AndroidManifest.xml -
<uses-permission android:name = "android.permission.READ_CONTACTS" />
Sekarang, pastikan daftar kontak memiliki setidaknya satu entri lalu jalankan pengujian menggunakan menu konteks Android Studio.