Yerel birim testleri oluşturma

Yerel test, Android cihaz veya emülatör yerine doğrudan kendi iş istasyonunuzda çalışır. Bu nedenle, testleri çalıştırmak için Android cihaz yerine yerel Java Sanal Makinenizi (JVM) kullanır. Yerel testler, uygulamanızın mantığını daha hızlı değerlendirmenizi sağlar. Ancak Android çerçevesiyle etkileşim kuramamak, çalıştırabileceğiniz test türlerini sınırlar.

Birim testi, kodun küçük bir bölümünün (test edilen birim) davranışını doğrular. Bunu, ilgili kodu çalıştırıp sonucu kontrol ederek yapar.

Birim testleri genellikle basittir ancak test edilen birim test edilebilirlik göz önünde bulundurularak tasarlanmadığında kurulumu sorunlu olabilir:

  • Doğrulamak istediğiniz kodun bir testten erişilebilir olması gerekir. Örneğin, özel bir yöntemi doğrudan test edemezsiniz. Bunun yerine, sınıfı herkese açık API'lerini kullanarak test edersiniz.
  • Birim testlerini izole olarak çalıştırmak için test edilen birimin bağımlılıkları, kontrol ettiğiniz bileşenlerle (ör. sahte bileşenler veya diğer test çiftleri) değiştirilmelidir. Bu durum, özellikle kodunuz Android çerçevesine bağlıysa sorun yaratır.

Android'deki yaygın birim testi stratejileri hakkında bilgi edinmek için Neleri test etmelisiniz? başlıklı makaleyi okuyun.

Yerel testlerin konumu

Varsayılan olarak, yerel birim testlerinin kaynak dosyaları module-name/src/test/ dizinine yerleştirilir. Android Studio'yu kullanarak yeni bir proje oluşturduğunuzda bu dizin zaten mevcuttur.

Test bağımlılıkları ekleme

Ayrıca, JUnit test çerçevesi tarafından sağlanan standart API'leri kullanmak için projenizin test bağımlılıklarını yapılandırmanız gerekir.

Bunun için uygulamanızın modülünün build.gradle dosyasını açın ve aşağıdaki kitaplıkları bağımlılık olarak belirtin. Bunların uygulamaya değil, yerel test kaynak grubuna uygulandığını belirtmek için testImplementation işlevini kullanın:

dependencies {
  // Required -- JUnit 4 framework
  testImplementation "junit:junit:$jUnitVersion"
  // Optional -- Robolectric environment
  testImplementation "androidx.test:core:$androidXTestVersion"
  // Optional -- Mockito framework
  testImplementation "org.mockito:mockito-core:$mockitoVersion"
  // Optional -- mockito-kotlin
  testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
  // Optional -- Mockk framework
  testImplementation "io.mockk:mockk:$mockkVersion"
}

Yerel birim testi sınıfı oluşturma

Yerel birim testi sınıfınızı JUnit 4 test sınıfı olarak yazarsınız.

Bunun için genellikle module-name/src/test/ içinde bir veya daha fazla test yöntemi içeren bir sınıf oluşturun. Test yöntemi @Test ek açıklamasıyla başlar ve test etmek istediğiniz bileşenin tek bir yönünü uygulamak ve doğrulamak için gereken kodu içerir.

Aşağıdaki örnekte, yerel birim testi sınıfının nasıl uygulanacağı gösterilmektedir. Test yöntemi, uygulamadaki bir yöntem olan isValidEmail() yöntemini doğrulamaya çalışır. isValidEmail() da doğru değerini döndürürse test işlevi doğru değerini döndürür.emailValidator_correctEmailSimple_returnsTrue()

Kotlin

import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class EmailValidatorTest {
  @Test fun emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"))
  }

}

Java

import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

class EmailValidatorTest {
  @Test
  public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"));
  }
}

Uygulamanızdaki bileşenlerin beklenen sonuçları döndürüp döndürmediğini değerlendiren okunabilir testler oluşturmanız gerekir. junit.Assert, Hamcrest veya Truth gibi bir onaylama kitaplığı kullanmanızı öneririz. Yukarıdaki snippet, junit.Assert öğesinin nasıl kullanılacağına dair bir örnektir.

Taklit edilebilir Android kitaplığı

Yerel birim testlerini çalıştırdığınızda Android Gradle eklentisi, projenizde kullanılan sürüme uygun olarak Android çerçevesinin tüm API'lerini içeren bir kitaplık içerir. Kitaplık, bu API'lerin tüm herkese açık yöntemlerini ve sınıflarını içerir ancak yöntemlerin içindeki kod kaldırılmıştır. Yöntemlerden herhangi birine erişilirse test bir istisna hatası verir.

Bu sayede, Android çerçevesindeki Context gibi sınıflara referans verilirken yerel testler oluşturulabilir. Daha da önemlisi, Android sınıflarıyla bir taklit çerçevesi kullanmanıza olanak tanır.

Android bağımlılıklarını taklit etme

Sık karşılaşılan sorunlardan biri, bir sınıfın dize kaynağı kullandığını fark etmektir. Context sınıfındaki getString() yöntemini çağırarak dize kaynaklarını alabilirsiniz. Ancak yerel testler, Android çerçevesine ait oldukları için Context sınıfını veya yöntemlerini kullanamaz. İdeal olarak, getString() çağrısı sınıftan çıkarılmalıdır ancak bu her zaman mümkün olmayabilir. Çözüm, getString() yöntemi çağrıldığında her zaman aynı değeri döndüren bir Context taklidi veya taslağı oluşturmaktır.

Mockable Android kitaplığı ve Mockito veya MockK gibi taklit çerçeveleriyle, birim testlerinizde Android sınıflarının taklitlerinin davranışını programlayabilirsiniz.

Mockito kullanarak yerel birim testinize bir sahte nesne eklemek için aşağıdaki programlama modelini uygulayın:

  1. Test ortamınızı ayarlama bölümünde açıklandığı gibi, Mockito kitaplığı bağımlılığını build.gradle dosyanıza ekleyin.
  2. Birim testi sınıf tanımınızın başına @RunWith(MockitoJUnitRunner.class) ek açıklamasını ekleyin. Bu ek açıklama, Mockito test çalıştırıcısına çerçeveyi doğru şekilde kullandığınızı doğrulamasını söyler ve sahte nesnelerinizin başlatılmasını basitleştirir.
  3. Bir Android bağımlılığı için sahte nesne oluşturmak istiyorsanız alan beyanından önce @Mock ek açıklamasını ekleyin.
  4. Bağımlılığın davranışını taklit etmek için when() ve thenReturn() yöntemlerini kullanarak bir koşul ve koşul karşılandığında döndürülecek değeri belirtebilirsiniz.

Aşağıdaki örnekte, Mockito-Kotlin ile oluşturulmuş Kotlin'de sahte bir Context nesnesi kullanan birim testinin nasıl oluşturulacağı gösterilmektedir.

import android.content.Context
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock

private const val FAKE_STRING = "HELLO WORLD"

@RunWith(MockitoJUnitRunner::class)
class MockedContextTest {

  @Mock
  private lateinit var mockContext: Context

  @Test
  fun readStringFromContext_LocalizedString() {
    // Given a mocked Context injected into the object under test...
    val mockContext = mock<Context> {
        on { getString(R.string.name_label) } doReturn FAKE_STRING
    }

    val myObjectUnderTest = ClassUnderTest(mockContext)

    // ...when the string is returned from the object under test...
    val result: String = myObjectUnderTest.getName()

    // ...then the result should be the expected one.
    assertEquals(result, FAKE_STRING)
  }
}

Mockito çerçevesini kullanma hakkında daha fazla bilgi edinmek için Mockito API referansına ve örnek koddaki SharedPreferencesHelperTest sınıfına bakın. Android Test Codelab'ini de deneyebilirsiniz.

Hata: "Method ... not mocked" (Yöntem ... taklit edilmedi)

Mockable Android kitaplığı, Error: "Method ... not mocked mesajıyla yöntemlerinden herhangi birine erişmeye çalışırsanız bir istisna oluşturur.

Oluşturulan istisnalar testleriniz için sorun teşkil ediyorsa davranışı değiştirerek yöntemlerin dönüş türüne bağlı olarak null veya sıfır döndürmesini sağlayabilirsiniz. Bunu yapmak için projenizin üst düzey build.gradle dosyasına Groovy'de aşağıdaki yapılandırmayı ekleyin:

android {
  ...
  testOptions {
    unitTests.returnDefaultValues = true
  }