Tujuan
Pada Codelab kali ini Anda akan menggunakan Junit untuk melakukan testing pada aplikasi MyViewModel yang sudah dibuat. Poin penting materi ini adalah agar Anda mengerti bagaimana menggunakan JUnit untuk melakukan pengujian pada aplikasi Anda.Logika Dasar
Menjalankan Aplikasi → menguji secara manual → menguji dengan Unit Testing → mendapat hasil pengujian secara otomatis.Codelab Pengujian ViewModel dengan Unit Testing
- Anda bisa membuka proyek sebelumnya, MyViewModel atau unduh di tautan berikut:
MyViewModel - Tambahkan terlebih dahulu library Unit Testing ke dalam project Anda. Bukalah build.gradle , masukkan kode berikut di dalamnya, dan jangan lupa untuk Sync Project.
testImplementation 'junit:junit:4.12'
testImplementation group: 'org.mockito', name: 'mockito-core', version: '3.1.0' - Selanjutnya, buat kelas baru untuk melakukan pengujian. Untuk membuatnya secara otomatis, buka kelas MainViewModel kemudian klik Alt+Enter pada MainViewModel maka akan ada banyak pilihan seperti berikut:
Anda perlu memberi checklist pada method calculate pada gambar di atas. Biarkan default nama kelas yang baru, MainViewModelTest. Klik OK untuk melanjutkan.Kotlin Setelah itu, pilih Create Test. Java Setelah itu, pilih Create Test. - Setelah itu, Anda diminta untuk menentukan di mana lokasi MainViewModelTest akan dibentuk. Pilihlah .../test/.... Mengapa demikian? Directory test digunakan untuk unit Testing, sedangkan directory androidTest digunakan untuk instrumental testing yang nanti akan dibahas pada modul selanjutnya. Klik OK untuk melanjutkan.
- Maka secara otomatis akan ada satu berkas baru seperti ini:
Sesuai dengan directory yang Anda pilih sebelumnya, kelas MainViewModelTest berada pada directory test. - Ok, sekarang buka kelas MainViewModelTest. Jika dilihat kode hasil generator menjadi seperti ini:
Kotlin |
class MainViewModelTest { |
Java |
public class MainViewModelTest { |
- Alangkah baiknya kita buka kembali kelas MainViewModel agar Anda paham apa yang mau diuji. Seperti ini kode pada kelas MainViewModel:
Di dalam MainViewModel terdapat 1 variable result dan 1 metode calculate.Kotlin class MainViewModel : ViewModel() {
var result = 0
fun calculate(width: String, height: String, length: String) {
result = width.toInt() * height.toInt() * length.toInt()
}
}Java public class MainViewModel extends ViewModel {
int result = 0;
void calculate(String width, String height, String length) {
result = Integer.parseInt(width) * Integer.parseInt(height) * Integer.parseInt(length);
}
} - Pertama, kita akan uji antara apa yang Anda masukan di calculate dengan hasil dari result. Tambahkan dan ubahlah kelas MainViewModelTest menjadi seperti ini:
Kode di atas digunakan untuk memastikan apakah hasil dari mainViewModel.result sesuai dengan yang diharapkan.Kotlin class MainViewModelTest {
private lateinit var mainViewModel: MainViewModel
@Before
fun init() {
mainViewModel = MainViewModel()
}
@Test
fun calculate() {
val width = "1"
val length = "2"
val height = "3"
mainViewModel.calculate(width, height, length)
assertEquals(6, mainViewModel.result)
}
}Java public class MainViewModelTest {
private MainViewModel mainViewModel;
@Before
public void init() {
mainViewModel = new MainViewModel();
}
@Test
public void calculate() {
String width = "1";
String length = "2";
String height = "3";
mainViewModel.calculate(width, height, length);
assertEquals(6, mainViewModel.result);
}
} - Oke, Anda bisa jalankan pengujian pertama Anda. Klik bagian ini untuk melakukan pengujian.
Kemudian pilih Run ‘MainViewModelTest’. - Android Studio akan menjalankan pengujian kelas MainViewModelTest dan akan menghasilkan skenario seperti ini.
Gambar di atas menunjukkan bahwa pengujian yang Anda lakukan berhasil. Itu bisa dilihat dengan adanya checklist berwarna hijau pada proses pengujian. - Oke, selanjutnya kita Akan coba ketika inputan berbeda dengan ekspektasi. Ubahlah kode di kelas MainViewModelTest menjadi seperti ini:
Kotlin class MainViewModelTest {
private lateinit var mainViewModel: MainViewModel
@Before
fun init() {
mainViewModel = MainViewModel()
}
@Test
fun calculate() {
val width = "1"
val length = "2"
val height = "2"
mainViewModel.calculate(width, height, length)
assertEquals(6, mainViewModel.result)
}
}Java public class MainViewModelTest {
private MainViewModel mainViewModel;
@Before
public void init() {
mainViewModel = new MainViewModel();
}
@Test
public void calculate() {
String width = "1";
String length = "2";
String height = "2";
mainViewModel.calculate(width, height, length);
assertEquals(6, mainViewModel.result);
}
} - Jalankan pengujian tersebut, maka akan seperti ini:
Ekspektasi dari pengujian adalah 6, namun dalam pengujian aktualnya adalah 4. Tentu tak sesuai antara aktual dengan ekspektasi, maka pengujian dianggap gagal. Oke, Anda bisa sesuaikan kembali nilai height agar aktual dengan ekspektasi sama. - Selanjutnya, kita akan coba input di dalam string menjadi double bukan integer. Tambahkan kode seperti ini:
Kotlinclass MainViewModelTest {
...
@Test
fun doubleInputCalculateTest() {
val width = "1"
val length = "2.4"
val height = "3"
mainViewModel.calculate(width, height, length)
}
}
Javapublic class MainViewModelTest {
...
@Test
public void doubleInputCalculateTest() {
String width = "1";
String length = "2.4";
String height = "3";
mainViewModel.calculate(width, height, length);
}
} - Jalankan pengujian tersebut, maka akan menjadi seperti ini:Pengujian yang dilakukan gagal, karena apa yang Anda masukan dalam string bukanlah integer melainkan double. Ini mungkin saja terjadi dalam kejadian-kejadian tertentu, namun Anda perlu mengantisipasi kejadian tersebut.
Annotation @Rule digunakan untuk untuk menjalankan kode sebelum pengujian dilakukan. Jadi jika tidak diberi anotasi @Rule pada thrown, maka kode tersebut tidak akan berjalan.
Kotlinclass MainViewModelTest {
...
@get:Rule
var thrown = ExpectedException.none()
...
@Test
@Throws(NumberFormatException::class)
fun doubleInputCalculateTest() {
val width = "1"
val length = "2.4"
val height = "3"
thrown.expect(NumberFormatException::class.java)
thrown.expectMessage("For input string: \"2.4\"")
mainViewModel.calculate(width, height, length)
}
}
Javapublic class MainViewModelTest {
...
@Rule
public ExpectedException thrown = ExpectedException.none();
...
@Test
public void doubleInputCalculateTest() throws NumberFormatException {
String width = "1";
String length = "2.4";
String height = "3";
thrown.expect(NumberFormatException.class);
thrown.expectMessage("For input string: \"2.4\"");
mainViewModel.calculate(width, height, length);
}
} - Karena eror tersebut berasal dari NumberFormatException, maka Anda bisa menambahkan itu dengan cara seperti ini:
- Jalankan kode tersebut, maka hasilnya akan menjadi seperti ini:
Lihat hasil di atas! Pengujian Anda berhasil. Sesuai Ekspektasi Anda bahwa eror tersebut terjadi karena NumberFormatException, bahkan Anda juga mencocokkan pesan dari eror yang terjadi dengan ekspektasi Anda.
NumberFormatException akan terjadi saat Anda mencoba mengubah String menjadi nilai angka namun String tersebut tidak terformat dengan benar. Misalnya dalam kasus tersebut ekspektasi Anda adalah Integer, namun aktualnya adalah String. - Selanjutnya tambahkan kode berikut untuk memberi ekspektasi eror yang terjadi saat ada input kosong dan berupa character:
Kotlinclass MainViewModelTest {
...
@Test
@Throws(java.lang.NumberFormatException::class)
fun characterInputCalculateTest() {
val width = "1"
val length = "A"
val height = "3"
thrown.expect(java.lang.NumberFormatException::class.java)
thrown.expectMessage("For input string: \"A\"")
mainViewModel.calculate(width, length, height)
}
@Test
@Throws(java.lang.NumberFormatException::class)
fun emptyInputCalculateTest() {
val width = "1"
val length = ""
val height = "3"
thrown.expect(java.lang.NumberFormatException::class.java)
thrown.expectMessage("For input string: \"\"")
mainViewModel.calculate(width, height, length)
}
}
Javapublic class MainViewModelTest {
...
@Test
public void characterInputCalculateTest() throws NumberFormatException {
String width = "1";
String length = "A";
String height = "3";
thrown.expect(NumberFormatException.class);
thrown.expectMessage("For input string: \"A\"");
mainViewModel.calculate(width, length, height);
}
@Test
public void emptyInputCalculateTest() throws NumberFormatException {
String width = "1";
String length = "";
String height = "3";
thrown.expect(NumberFormatException.class);
thrown.expectMessage("For input string: \"\"");
mainViewModel.calculate(width, height, length);
}
} - Anda bisa menjalankan kembali pengujian yang Anda buat, maka akan menjadi seperti ini:
Tentu, pengujian di atas berhasil dilakukan karena Anda sudah memberi ekspektasi eror yang terjadi. Untuk pengujian, Anda bisa melakukan sesuai dengan kebutuhan dari aplikasi Anda.
Bedah Kode
Kita sudah melewati beberapa latihan untuk melakukan UnitTest. Pada modul sebelumnya juga Anda sudah mempelajari tentang Unit Test.Perhatikan kode berikut:
Kotlin |
private lateinit var mainViewModel: MainViewModel |
Java |
private MainViewModel mainViewModel; |
Untuk menginisialisasi ViewModel, Anda perlu melakukannya di dalam method init() dengan anotasi @Before. Anotasi ini berfungsi untuk melakukan serangkaian persiapan sebelum melakukan pengujian.
Perhatikan kode berikut:
Kotlin |
@Test |
Java |
@Test |
Kode assertEquals berguna untuk membandingkan antara ekspektasi dan hasil aktual perhitungan. Jika Anda masih belum paham tentang pengujian, Anda bisa cek kembali modul 0 tentang pengujian.
Perhatikan kode berikut:
Kotlin |
@get:Rule |
Java |
@Rule |
Kode di atas berguna untuk memastikan apakah pesan eror yang terjadi sesuai dengan ekspektasi Anda.
Pada kasus di atas, ekspektasinya yaitu variable yang dimasukkan bukan integer, melainkan double. Untuk menggunakan ExpectedException, Anda perlu menggunakan anotasi Rule untuk memberi aturan pada pengujian .
Jika Anda masih belum paham tentang pengujian, Anda bisa cek kembali modul 0 tentang pengujian.
Source code dapat Anda unduh pada tautan berikut: