Tujuan
Logika Dasar
Instrumental Testing: Melakukan pengujian tiap halaman dan keseluruhan Aplikasi.
Codelab Unit Testing ViewModel
-
Bukalah proyek Academy yang sudah Anda buat pada modul sebelumnya atau Anda bisa unduh di sini:
-
Pertama yang perlu dilakukan adalah menuliskan skenario testing yang dilakukan:
-
AcademyViewModelTest:
-
Memuat Courses:
- Memastikan data course tidak null.
- Memastikan jumlah data course sesuai dengan yang diharapkan.
-
- BookmarkViewModelTest:
-
Memuat Bookmarks:
- Memastikan data course tidak null.
- Memastikan jumlah data course sesuai dengan yang diharapkan.
-
- DetailCourseViewModelTest:
-
Memuat Course:
- Memastikan data course tidak null.
- Memastikan data course sesuai dengan yang diharapkan.
- Memuat Modules:
- Memastikan data module tidak null.
- Memastikan jumlah data module sesuai dengan yang diharapkan.
-
- CourseReaderViewModelTest:
- Memuat Modules:
- Memastikan data module tidak null.
- Memastikan jumlah data module sesuai dengan yang diharapkan.
- Memuat Module yang dipilih:
- Memastikan data module tidak null.
- Memastikan data content tidak null.
- Memastikan value dari content tidak null.
- Memastikan data content sesuai dengan yang diharapkan.
- Memuat Modules:
-
- Bukalah AcademyViewModel, kemudian klik ALT + Enter di bagian AcademyViewModel seperti ini:
Kotlin Java Kemudian pilih Create Test, maka akan muncul tampilan seperti ini:
Biarkan nama default seperti tampilan di atas, kemudian tekan tombol OK maka akan muncul pilihan tujuan pembuatan kelas. Karena Anda akan melakukan Unit Testing, maka pilih folder test.
Tekan tombol OK maka secara otomatis akan ada sebuah kelas baru dengan nama AcademyViewModelTesting.
Catatan:Hapuslah ExampleUnitTest, karena kita tidak akan memakai kelas tersebut. -
Selanjutnya, bukalah kelas AcademyViewModelTest. Ujilah metode getCourses() dengan memasukkan kode berikut:
Kotlin class AcademyViewModelTest { private lateinit var viewModel: AcademyViewModel @Before fun setUp() { viewModel = AcademyViewModel() } @Test fun getCourses() { val courseEntities = viewModel.getCourses() assertNotNull(courseEntities) assertEquals(5, courseEntities.size) } }
Java public class AcademyViewModelTest { private AcademyViewModel viewModel; @Before public void setUp() { viewModel = new AcademyViewModel(); } @Test public void getCourses() { List<CourseEntity> courseEntities = viewModel.getCourses(); assertNotNull(courseEntities); assertEquals(5, courseEntities.size()); } }
-
Jalankan pengujian pada kelas AcademyViewModelTest, dengan cara menekan tombol di sebelah kiri kode editor.
Pilihlah Run ‘AcademyViewModelTest’, maka hasil pengujiannya jadi seperti ini:
Selamat, Anda berhasil menguji AcademyViewModel dengan cara membandingkan ukuran dari array viewModel.getCourses(). -
Lakukanlah kembali langkah nomor 2 untuk melakukan Unit Testing kelas BookmarkViewModel, DetailCoursesViewModel dan CourseReaderViewModel. Jika Anda sudah melakukan langkah tersebut, maka tampilan kelas pada package test akan jadi seperti ini:
-
Bukalah BookmarkViewModelTest, kita akan menguji apakah metode getBookmark sudah benar atau belum. Tambahkan kode berikut:
Kotlin class BookmarkViewModelTest { private lateinit var viewModel: BookmarkViewModel @Before fun setUp() { viewModel = BookmarkViewModel() } @Test fun getBookmark() { val courseEntities = viewModel.getBookmarks() assertNotNull(courseEntities) assertEquals(5, courseEntities.size) } }
Java public class BookmarkViewModelTest { private BookmarkViewModel viewModel; @Before public void setUp() { viewModel = new BookmarkViewModel(); } @Test public void getBookmark() { List<CourseEntity> courseEntities = viewModel.getBookmarks(); assertNotNull(courseEntities); assertEquals(5, courseEntities.size()); } }
Jika dilihat dari kode di atas, cara pengujian yang dilakukan sama karena data bookmark sama-sama berasal dari kelas DataDummy. Jalankan pengujian tersebut, maka akan jadi seperti ini:
Sekali lagi, selamat! Anda berhasil melakukan pengujian BookmarkViewModel dengan unit testing. Tapi masih ada 2 kelas ViewModel lagi yang perlu diuji. - Bukalah kelas DetailCourseViewModelTest. Pada kelas ini, terdapat 2 metode sumber data yakni getCourse() dan getModules(). Tambahkan kode berikut untuk melakukan pengujian terhadap 2 metode tersebut:
Kotlin class DetailCourseViewModelTest { private lateinit var viewModel: DetailCourseViewModel private val dummyCourse = DataDummy.generateDummyCourses()[0] private val courseId = dummyCourse.courseId @Before fun setUp() { viewModel = DetailCourseViewModel() viewModel.setSelectedCourse(courseId) } @Test fun getCourse() { viewModel.setSelectedCourse(dummyCourse.courseId) val courseEntity = viewModel.getCourse() assertNotNull(courseEntity) assertEquals(dummyCourse.courseId, courseEntity.courseId) assertEquals(dummyCourse.deadline, courseEntity.deadline) assertEquals(dummyCourse.description, courseEntity.description) assertEquals(dummyCourse.imagePath, courseEntity.imagePath) assertEquals(dummyCourse.title, courseEntity.title) } @Test fun getModules() { val moduleEntities = viewModel.getModules() assertNotNull(moduleEntities) assertEquals(7, moduleEntities.size.toLong()) } }
Java public class DetailCourseViewModelTest { private DetailCourseViewModel viewModel; private CourseEntity dummyCourse = DataDummy.generateDummyCourses().get(0); private String courseId = dummyCourse.getCourseId(); @Before public void setUp() { viewModel = new DetailCourseViewModel(); viewModel.setSelectedCourse(courseId); } @Test public void getCourse() { viewModel.setSelectedCourse(dummyCourse.getCourseId()); CourseEntity courseEntity = viewModel.getCourse(); assertNotNull(courseEntity); assertEquals(dummyCourse.getCourseId(), courseEntity.getCourseId()); assertEquals(dummyCourse.getDeadline(), courseEntity.getDeadline()); assertEquals(dummyCourse.getDescription(), courseEntity.getDescription()); assertEquals(dummyCourse.getImagePath(), courseEntity.getImagePath()); assertEquals(dummyCourse.getTitle(), courseEntity.getTitle()); } @Test public void getModules() { List<ModuleEntity> moduleEntities = viewModel.getModules(); assertNotNull(moduleEntities); assertEquals(7, moduleEntities.size()); } }
Jalankan pengujian pada kelas tersebut, maka hasil pengujiannya jadi seperti ini:
Selamat, Anda juga berhasil menguji DetailCourseViewModel dengan cara membandingkan ukuran dari array viewModel.getModules() dan membandingkan data CourseEntity hasil dari viewModel.getCourses().
-
Terakhir, bukalah CourseReaderViewModelTest. Pada kelas CourseReaderViewModel, terdapat 2 metode yang harus diuji yakni getSelectedModule dan getModules. Tambahkan kode berikut untuk melakukan pengujian:
Kotlin class CourseReaderViewModelTest { private lateinit var viewModel: CourseReaderViewModel private val dummyCourse = DataDummy.generateDummyCourses()[0] private val courseId = dummyCourse.courseId private val dummyModules = DataDummy.generateDummyModules(courseId) private val moduleId = dummyModules[0].moduleId @Before fun setUp() { viewModel = CourseReaderViewModel() viewModel.setSelectedCourse(courseId) viewModel.setSelectedModule(moduleId) val dummyModule = dummyModules[0] dummyModule.contentEntity = ContentEntity("<h3 class=\"fr-text-bordered\">"+dummyModule.title+"</h3><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>") } @Test fun getModules() { val moduleEntities = viewModel.getModules() assertNotNull(moduleEntities) assertEquals(7, moduleEntities.size.toLong()) } @Test fun getSelectedModule() { val moduleEntity = viewModel.getSelectedModule() assertNotNull(moduleEntity) val contentEntity = moduleEntity.contentEntity assertNotNull(contentEntity) val content = contentEntity?.content assertNotNull(content) assertEquals(content, dummyModules[0].contentEntity?.content) } }
Java public class CourseReaderViewModelTest { private CourseReaderViewModel viewModel; private CourseEntity dummyCourse = DataDummy.generateDummyCourses().get(0); private String courseId = dummyCourse.getCourseId(); private ArrayList<ModuleEntity> dummyModules = DataDummy.generateDummyModules(courseId); private String moduleId = dummyModules.get(0).getModuleId(); @Before public void setUp() { viewModel = new CourseReaderViewModel(); viewModel.setSelectedCourse(courseId); viewModel.setSelectedModule(moduleId); ModuleEntity dummyModule = dummyModules.get(0); dummyModule.contentEntity = new ContentEntity("<h3 class=\"fr-text-bordered\">" + dummyModule.getTitle() + "</h3><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>"); } @Test public void getModules() { ArrayList<ModuleEntity> moduleEntities = viewModel.getModules(); assertNotNull(moduleEntities); assertEquals(7, moduleEntities.size()); } @Test public void getSelectedModule() { ModuleEntity moduleEntity = viewModel.getSelectedModule(); assertNotNull(moduleEntity); ContentEntity contentEntity = moduleEntity.contentEntity; assertNotNull(contentEntity); String content = contentEntity.getContent(); assertNotNull(content); assertEquals(content, dummyModules.get(0).contentEntity.getContent()); } }
Jalankan pengujian pada kelas tersebut, maka hasil pengujiannya jadi seperti ini:
Selamat, Anda juga berhasil menguji CourseReaderViewModel dengan cara membandingkan ukuran dari array viewModel.getModules() dan membandingkan data ModuleEntity hasil dari viewModel.getSelectedModule().
Codelab Instrumental Testing ViewModel
-
Sebelum Anda melakukan Instrumental Testing, Anda perlu membuat skenario testing yang dilakukan:
- Menampilkan data kursus academy
- Memastikan rv_academy dalam keadaan tampil.
- Gulir rv_academy ke posisi data terakhir.
- Menampilkan data detail kursus academy
- Memberi tindakan klik pada data pertama di rv_academy.
- Memastikan TextView untuk title tampil sesuai dengan yang diharapkan.
- Memastikan TextView untuk deadline tampil sesuai dengan yang diharapkan.
- Menampilkan data modul
- Memberi tindakan klik pada data pertama di rv_academy.
- Memberi tindakan klik pada btn_start.
- Memastikan rv_module dalam keadaan tampil.
- Menampilkan data kursus academy
- Memberi tindakan klik pada data pertama di rv_academy.
- Memberi tindakan klik pada btn_start.
- Memberi tindakan klik pada data pertama di rv_module
- Memastikan web_view sudah tampil.
- Menampilkan data bookmark
- Klik TabLayout dengan teks Bookmark
- Memastikan rv_module dalam keadaan tampil.
- Gulir rv_module ke posisi data terakhir.
- Menampilkan data kursus academy
-
Selanjutnya Anda perlu menambahkan library yang digunakan untuk pengujian. Bukalah build.gradle (project), tambahkan kode berikut:
ext { //dependencies version appCompatVersion = '1.1.0' coreVersion = '1.1.0' constraintLayoutVersion = '1.1.3' junitVersion = '4.12' espressoVersion = '3.1.0' androidXTestVersion = '1.2.0' materialVersion = '1.0.0' recyclerViewVersion = '1.1.0' glideVersion = '4.10.0' archLifecycleVersion = '2.1.0' }
Kemudian bukalah build.gradle (module:app), tambahkan kode berikut:androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" androidTestImplementation "androidx.test:rules:$androidXTestVersion"
-
Bukalah HomeActivity, kemudian klik ALT + Enter di bagian HomeActivity seperti ini:
Kotlin Java Kemudian pilih Create Test, maka akan muncul tampilan seperti ini:
Biarkan nama default seperti tampilan di atas, kemudian tekan tombol OK maka akan muncul pilihan tujuan pembuatan kelas. Karena Anda akan melakukan Instrumental Testing, maka pilih folder androidTest.
Tekan tombol OK, secara otomatis akan ada sebuah kelas baru dengan nama HomeActivityTest.
Catatan:Hapuslah ExampleInstrumentedTest, karena kita tidak akan memakai kelas tersebut. -
Bukalah kelas HomeAcademyTest, buatlah pengujian sesuai dengan skenario seperti berikut:
Kotlin class HomeActivityTest { private val dummyCourse = DataDummy.generateDummyCourses() @get:Rule var activityRule = ActivityTestRule(HomeActivity::class.java) @Test fun loadCourses() { onView(withId(R.id.rv_academy)).check(matches(isDisplayed())) onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.scrollToPosition<RecyclerView.ViewHolder>(dummyCourse.size)) } @Test fun loadDetailCourse() { onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(0, click())) onView(withId(R.id.text_title)).check(matches(isDisplayed())) onView(withId(R.id.text_title)).check(matches(withText(dummyCourse[0].title))) onView(withId(R.id.text_date)).check(matches(isDisplayed())) onView(withId(R.id.text_date)).check(matches(withText("Deadline ${dummyCourse[0].deadline}"))) } @Test fun loadModule() { onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(0, click())) onView(withId(R.id.btn_start)).perform(click()) onView(withId(R.id.rv_module)).check(matches(isDisplayed())) } @Test fun loadDetailModule() { onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(0, click())) onView(withId(R.id.btn_start)).perform(click()) onView(withId(R.id.rv_module)).perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(0, click())) onView(withId(R.id.web_view)).check(matches(isDisplayed())) } @Test fun loadBookmarks() { onView(withText("Bookmark")).perform(click()) onView(withId(R.id.rv_bookmark)).check(matches(isDisplayed())) onView(withId(R.id.rv_bookmark)).perform(RecyclerViewActions.scrollToPosition<RecyclerView.ViewHolder>(dummyCourse.size)) } }
Java public class HomeActivityTest { private ArrayList<CourseEntity> dummyCourse = DataDummy.generateDummyCourses(); @Rule public ActivityTestRule activityRule = new ActivityTestRule<>(HomeActivity.class); @Test public void loadCourses() { onView(withId(R.id.rv_academy)).check(matches(isDisplayed())); onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.scrollToPosition(dummyCourse.size())); } @Test public void loadDetailCourse() { onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); onView(withId(R.id.text_title)).check(matches(isDisplayed())); onView(withId(R.id.text_title)).check(matches(withText(dummyCourse.get(0).getTitle()))); onView(withId(R.id.text_date)).check(matches(isDisplayed())); onView(withId(R.id.text_date)).check(matches(withText(String.format("Deadline %s", dummyCourse.get(0).getDeadline())))); } @Test public void loadModule() { onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); onView(withId(R.id.btn_start)).perform(click()); onView(withId(R.id.rv_module)).check(matches(isDisplayed())); } @Test public void loadDetailModule() { onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); onView(withId(R.id.btn_start)).perform(click()); onView(withId(R.id.rv_module)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); onView(withId(R.id.web_view)).check(matches(isDisplayed())); } @Test public void loadBookmarks() { onView(withText("Bookmark")).perform(click()); onView(withId(R.id.rv_bookmark)).check(matches(isDisplayed())); onView(withId(R.id.rv_bookmark)).perform(RecyclerViewActions.scrollToPosition(dummyCourse.size())); } }
- Kemudian jalankan test dengan cara klik kanan pada class HomeActivityTest dan klik Run ‘HomeActivityTest’.
Bisa juga dengan klik icon hijau seperti gambar ini:
Maka device akan otomatis melakukan aksi sesuai dengan yang diskenariokan seperti ini:
Dan kalau dilihat hasil testnya seperti ini:Selamat! Anda berhasil menguji AcademyTest.
Bedah Kode
UnitTest
Tiga Komponen Utama dari Espresso:
-
ViewMatchers (onView(ViewMatcher)): untuk menemukan elemen atau komponen antarmuka yang diuji.
-
ViewActions (perform(ViewAction)): untuk memberikan event untuk melakukan sebuah aksi pada komponen antarmuka yang diuji.
-
ViewAssertions: sebuah kondisi atau state dari komponen yang diuji.
Kotlin |
@get:Rule var activityRule = ActivityTestRule(HomeActivity::class.java) |
Java |
@Rule public ActivityTestRule activityRule = new ActivityTestRule<>(HomeActivity.class); |
Kotlin |
onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.scrollToPosition<RecyclerView.ViewHolder>(dummyCourse.size)) ... onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(0, click())) |
Java |
onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.scrollToPosition(dummyCourse.size())); ... onView(withId(R.id.rv_academy)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); |
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"