Hilt test kılavuzu

Hilt gibi bağımlılık yerleştirme çerçevelerini kullanmanın avantajlarından biri, kodunuzu test etmeyi kolaylaştırmasıdır.

Birim testleri

Kurucu yerleştirme tekniğinin kullanıldığı bir sınıfı test ederken bu sınıfı örneklendirmek için Hilt'i kullanmanız gerekmediğinden, birim testleri için Hilt gerekli değildir. Bunun yerine, oluşturucuya açıklama eklenmediğinde olduğu gibi sahte veya sahte bağımlılıklar ileterek doğrudan bir sınıf oluşturucu çağırabilirsiniz:

Kotlin

@ActivityScoped
class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }

class AnalyticsAdapterTest {

  @Test
  fun `Happy path`() {
    // You don't need Hilt to create an instance of AnalyticsAdapter.
    // You can pass a fake or mock AnalyticsService.
    val adapter = AnalyticsAdapter(fakeAnalyticsService)
    assertEquals(...)
  }
}

Java

@ActivityScope
public class AnalyticsAdapter {

  private final AnalyticsService analyticsService;

  @Inject
  AnalyticsAdapter(AnalyticsService analyticsService) {
    this.analyticsService = analyticsService;
  }
}

public final class AnalyticsAdapterTest {

  @Test
  public void happyPath() {
    // You don't need Hilt to create an instance of AnalyticsAdapter.
    // You can pass a fake or mock AnalyticsService.
    AnalyticsAdapter adapter = new AnalyticsAdapter(fakeAnalyticsService);
    assertEquals(...);
  }
}

Uçtan uca testler

Hilt, entegrasyon testleri için bağımlılıkları üretim kodunuzda olduğu gibi ekler. Hilt, her test için otomatik olarak yeni bir bileşen grubu oluşturduğundan, Hilt ile test yapmak bakım gerektirmez.

Test bağımlılıkları ekleme

Hilt'i testlerinizde kullanmak için projenize hilt-android-testing bağımlılığını dahil edin:

Eski

dependencies {
    // For Robolectric tests.
    testImplementation 'com.google.dagger:hilt-android-testing:2.44'
    // ...with Kotlin.
    kaptTest 'com.google.dagger:hilt-android-compiler:2.44'
    // ...with Java.
    testAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.44'


    // For instrumented tests.
    androidTestImplementation 'com.google.dagger:hilt-android-testing:2.44'
    // ...with Kotlin.
    kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.44'
    // ...with Java.
    androidTestAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.44'
}

Kotlin

dependencies {
    // For Robolectric tests.
    testImplementation("com.google.dagger:hilt-android-testing:2.44")
    // ...with Kotlin.
    kaptTest("com.google.dagger:hilt-android-compiler:2.44")
    // ...with Java.
    testAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.44")


    // For instrumented tests.
    androidTestImplementation("com.google.dagger:hilt-android-testing:2.44")
    // ...with Kotlin.
    kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.44")
    // ...with Java.
    androidTestAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.44")
}

Kullanıcı arayüzü test kurulumu

Hilt'i kullanan tüm kullanıcı arayüzü testlerine @HiltAndroidTest ile açıklama eklemeniz gerekir. Bu not, her test için Hilt bileşenlerini oluşturmaktan sorumludur.

Ayrıca, HiltAndroidRule öğesini test sınıfına eklemeniz gerekir. Bileşenlerin durumunu yönetir ve testinize ekleme yapmak için kullanılır:

Kotlin

@HiltAndroidTest
class SettingsActivityTest {

  @get:Rule
  var hiltRule = HiltAndroidRule(this)

  // UI tests here.
}

Java

@HiltAndroidTest
public final class SettingsActivityTest {

  @Rule
  public HiltAndroidRule hiltRule = new HiltAndroidRule(this);

  // UI tests here.
}

Ardından, testinizin, Hilt'in sizin için otomatik olarak oluşturduğu Application sınıfı hakkında bilgi sahibi olması gerekir.

Test uygulaması

Hilt'i destekleyen bir Application nesnesinde Hilt kullanan araçlı testler yürütmeniz gerekir. Kitaplık, testlerde kullanılmak üzere HiltTestApplication sağlar. Testleriniz için farklı bir temel uygulama gerekiyorsa Testler için özel uygulama bölümüne bakın.

Test uygulamanızı araçlı testlerinizde veya Robolectric testlerinizde çalışacak şekilde ayarlamanız gerekir. Aşağıdaki talimatlar Hilt'e özel değildir ancak testlerde çalıştırılacak özel bir uygulamanın nasıl belirtileceğine ilişkin genel yönergelerdir.

Test uygulamasını araçlı testlerde ayarlama

Hilt test uygulamasını araçlı testlerde kullanmak için yeni bir test çalıştırıcı yapılandırmanız gerekir. Bu, Hilt'in projenizdeki tüm araçlı testlerde çalışmasını sağlar. Aşağıdaki adımları uygulayın:

  1. androidTest klasöründe AndroidJUnitRunner uzantısını genişleten özel bir sınıf oluşturun.
  2. newApplication işlevini geçersiz kılın ve oluşturulan Hilt test uygulamasının adını iletin.

Kotlin

// A custom runner to set up the instrumented application class for tests.
class CustomTestRunner : AndroidJUnitRunner() {

    override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
        return super.newApplication(cl, HiltTestApplication::class.java.name, context)
    }
}

Java

// A custom runner to set up the instrumented application class for tests.
public final class CustomTestRunner extends AndroidJUnitRunner {

  @Override
  public Application newApplication(ClassLoader cl, String className, Context context)
      throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    return super.newApplication(cl, HiltTestApplication.class.getName(), context);
  }
}

Daha sonra, araçlı birim test kılavuzunda açıklandığı şekilde bu test çalıştırıcıyı Gradle dosyanızda yapılandırın. Sınıf yolunun tamamını kullandığınızdan emin olun:

Eski

android {
    defaultConfig {
        // Replace com.example.android.dagger with your class path.
        testInstrumentationRunner "com.example.android.dagger.CustomTestRunner"
    }
}

Kotlin

android {
    defaultConfig {
        // Replace com.example.android.dagger with your class path.
        testInstrumentationRunner = "com.example.android.dagger.CustomTestRunner"
    }
}
Robolectric testlerinde test uygulamasını ayarlama

Kullanıcı arayüzü katmanınızı test etmek için Robolectric'i kullanırsanız robolectric.properties dosyasında hangi uygulamanın kullanılacağını belirtebilirsiniz:

application = dagger.hilt.android.testing.HiltTestApplication

Alternatif olarak, Robolectric'in @Config ek açıklamasını kullanarak uygulamayı her bir testte ayrı ayrı yapılandırabilirsiniz:

Kotlin

@HiltAndroidTest
@Config(application = HiltTestApplication::class)
class SettingsActivityTest {

  @get:Rule
  var hiltRule = HiltAndroidRule(this)

  // Robolectric tests here.
}

Java

@HiltAndroidTest
@Config(application = HiltTestApplication.class)
class SettingsActivityTest {

  @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this);

  // Robolectric tests here.
}

4.2'den eski bir Android Gradle eklentisi kullanıyorsanız modülünüzün build.gradle dosyasında aşağıdaki yapılandırmayı uygulayarak yerel birim testlerinde @AndroidEntryPoint sınıflarını dönüştürmeyi etkinleştirin:

Eski

hilt {
    enableTransformForLocalTests = true
}

Kotlin

hilt {
    enableTransformForLocalTests = true
}

enableTransformForLocalTests hakkında daha fazla bilgiye Hilt belgelerinden ulaşabilirsiniz.

Test özellikleri

Hilt, testlerinizde kullanıma hazır olduğunda test sürecini özelleştirmek için çeşitli özellikleri kullanabilirsiniz.

Testlere türleri ekle

Bir teste tür eklemek için alan yerleştirme işleminde @Inject kullanın. Hilt'e @Inject alanlarını doldurmasını bildirmek için hiltRule.inject() işlevini çağırın.

Aşağıdaki araçlı test örneğine bakın:

Kotlin

@HiltAndroidTest
class SettingsActivityTest {

  @get:Rule
  var hiltRule = HiltAndroidRule(this)

  @Inject
  lateinit var analyticsAdapter: AnalyticsAdapter

  @Before
  fun init() {
    hiltRule.inject()
  }

  @Test
  fun `happy path`() {
    // Can already use analyticsAdapter here.
  }
}

Java

@HiltAndroidTest
public final class SettingsActivityTest {

  @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this);

  @Inject AnalyticsAdapter analyticsAdapter;

  @Before
  public void init() {
    hiltRule.inject();
  }

  @Test
  public void happyPath() {
    // Can already use analyticsAdapter here.
  }
}

Bağlamayı değiştirme

Bir bağımlılığın sahte veya sahte örneğini eklemeniz gerekiyorsa Hilt'e üretim kodunda kullandığı bağlamayı kullanmamasını ve bunun yerine farklı bir bağlama kullanmasını söylemeniz gerekir. Bir bağlamayı değiştirmek için bağlamayı içeren modülü, testte kullanmak istediğiniz bağlamaları içeren bir test modülüyle değiştirmeniz gerekir.

Örneğin, üretim kodunuzun AnalyticsService için bir bağlamayı aşağıdaki gibi tanımladığını varsayalım:

Kotlin

@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {

  @Singleton
  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}

Java

@Module
@InstallIn(SingletonComponent.class)
public abstract class AnalyticsModule {

  @Singleton
  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    AnalyticsServiceImpl analyticsServiceImpl
  );
}

Testlerdeki AnalyticsService bağlamasını değiştirmek için test veya androidTest klasöründe sahte bağımlılığa sahip yeni bir Hilt modülü oluşturun ve bu modüle @TestInstallIn ile açıklama ekleyin. Bunun yerine, söz konusu klasördeki tüm testler sahte bağımlılıkla enjekte edilir.

Kotlin

@Module
@TestInstallIn(
    components = [SingletonComponent::class],
    replaces = [AnalyticsModule::class]
)
abstract class FakeAnalyticsModule {

  @Singleton
  @Binds
  abstract fun bindAnalyticsService(
    fakeAnalyticsService: FakeAnalyticsService
  ): AnalyticsService
}

Java

@Module
@TestInstallIn(
    components = SingletonComponent.class,
    replaces = AnalyticsModule.class
)
public abstract class FakeAnalyticsModule {

  @Singleton
  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    FakeAnalyticsService fakeAnalyticsService
  );
}

Tek bir testte bağlamayı değiştirme

Tüm testler yerine tek bir testteki bağlamayı değiştirmek için @UninstallModules ek açıklamasını kullanarak testten bir Hilt modülünü kaldırın ve test içinde yeni bir test modülü oluşturun.

Önceki sürümdeki AnalyticsService örneğine göre, test sınıfında @UninstallModules ek açıklamasını kullanarak Hilt'e üretim modülünü yoksaymasını söyleyerek başlayın:

Kotlin

@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsActivityTest { ... }

Java

@UninstallModules(AnalyticsModule.class)
@HiltAndroidTest
public final class SettingsActivityTest { ... }

Ardından, bağlamayı değiştirmeniz gerekir. Test sınıfında, test bağlamasını tanımlayan yeni bir modül oluşturun:

Kotlin

@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsActivityTest {

  @Module
  @InstallIn(SingletonComponent::class)
  abstract class TestModule {

    @Singleton
    @Binds
    abstract fun bindAnalyticsService(
      fakeAnalyticsService: FakeAnalyticsService
    ): AnalyticsService
  }

  ...
}

Java

@UninstallModules(AnalyticsModule.class)
@HiltAndroidTest
public final class SettingsActivityTest {

  @Module
  @InstallIn(SingletonComponent.class)
  public abstract class TestModule {

    @Singleton
    @Binds
    public abstract AnalyticsService bindAnalyticsService(
      FakeAnalyticsService fakeAnalyticsService
    );
  }
  ...
}

Bu, yalnızca tek bir test sınıfı için bağlamanın yerini alır. Bağlamayı tüm test sınıfları için değiştirmek istiyorsanız yukarıdaki bölümde yer alan @TestInstallIn ek açıklamasını kullanın. Alternatif olarak, test bağlamasını Robolectric testleri için test modülüne veya araçlı testler için androidTest modülüne yerleştirebilirsiniz. Mümkün olduğunda @TestInstallIn kullanılması önerilir.

Yeni değerleri bağlama

Testinizdeki alanları Hilt bağımlılık grafiğine kolayca bağlamak için @BindValue ek açıklamasını kullanın. Bir alana @BindValue ile ek açıklama eklerseniz bu alan, belirtilen alan için mevcut olan tüm niteleyicilerle birlikte belirtilen alan türünün altına bağlanır.

AnalyticsService örneğinde, @BindValue kullanarak AnalyticsService yerine sahte bir değer girebilirsiniz:

Kotlin

@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsActivityTest {

  @BindValue @JvmField
  val analyticsService: AnalyticsService = FakeAnalyticsService()

  ...
}

Java

@UninstallModules(AnalyticsModule.class)
@HiltAndroidTest
class SettingsActivityTest {

  @BindValue AnalyticsService analyticsService = FakeAnalyticsService();

  ...
}

Bu, aynı anda her ikisini de yapmanızı sağlayarak testinizdeki bir bağlamayı değiştirmeyi ve bir bağlama referans verme sürecini basitleştirir.

@BindValue, niteleyicilerle ve diğer test ek açıklamalarıyla çalışır. Örneğin, Mockito gibi test kitaplıklarını kullanıyorsanız bunu Robolectric testinde aşağıdaki gibi kullanabilirsiniz:

Kotlin

...
class SettingsActivityTest {
  ...

  @BindValue @ExampleQualifier @Mock
  lateinit var qualifiedVariable: ExampleCustomType

  // Robolectric tests here
}

Java

...
class SettingsActivityTest {
  ...
  @BindValue @ExampleQualifier @Mock ExampleCustomType qualifiedVariable;

  // Robolectric tests here
}

Bir çoklu bağlama eklemeniz gerekiyorsa @BindValue yerine @BindValueIntoSet ve @BindValueIntoMap ek açıklamalarını kullanabilirsiniz. @BindValueIntoMap, alana bir harita anahtarı ek açıklaması eklemenizi de gerektirir.

Özel durumlar

Hilt, standart dışı kullanım alanlarını destekleyecek özellikler de sunar.

Testler için özel uygulama

Test uygulamanızın başka bir uygulamayı genişletmesi gerektiği için HiltTestApplication kullanamıyorsanız, oluşturulan Hilt uygulamasının kapsamını genişletmesini istediğiniz temel sınıfın değerini ileterek yeni sınıfa veya arayüze @CustomTestApplication ile açıklama ekleyin.

@CustomTestApplication, Hilt ile test edilmeye hazır olan bir Application sınıfı oluşturur. Bu sınıf, parametre olarak ilettiğiniz uygulamanın kapsamını genişletir.

Kotlin

@CustomTestApplication(BaseApplication::class)
interface HiltTestApplication

Java

@CustomTestApplication(BaseApplication.class)
interface HiltTestApplication { }

Aşağıdaki örnekte Hilt, BaseApplication sınıfını genişleten HiltTestApplication_Application adlı bir Application oluşturur. Genel olarak, oluşturulan uygulamanın adı _Application ile eklenen açıklama eklenen sınıfın adıdır. Oluşturulan Hilt test uygulamasını Test uygulaması bölümünde açıklandığı şekilde araçlı testlerinizde veya Robolectric testlerinizde çalışacak şekilde ayarlamanız gerekir.

Araçlı testinizde birden çok TestRule nesnesi

Testinizde başka TestRule nesneleri varsa tüm kuralların birlikte çalışmasını sağlamanın birden çok yolu vardır.

Kuralları aşağıdaki gibi bir araya getirebilirsiniz:

Kotlin

@HiltAndroidTest
class SettingsActivityTest {

  @get:Rule
  var rule = RuleChain.outerRule(HiltAndroidRule(this)).
        around(SettingsActivityTestRule(...))

  // UI tests here.
}

Java

@HiltAndroidTest
public final class SettingsActivityTest {

  @Rule public RuleChain rule = RuleChain.outerRule(new HiltAndroidRule(this))
        .around(new SettingsActivityTestRule(...));

  // UI tests here.
}

Alternatif olarak, önce HiltAndroidRule yürütüldüğü sürece her iki kuralı da aynı düzeyde kullanabilirsiniz. @Rule ek açıklamasındaki order özelliğini kullanarak yürütme siparişini belirtin. Bu işlem yalnızca JUnit 4.13 veya sonraki sürümlerde çalışır:

Kotlin

@HiltAndroidTest
class SettingsActivityTest {

  @get:Rule(order = 0)
  var hiltRule = HiltAndroidRule(this)

  @get:Rule(order = 1)
  var settingsActivityTestRule = SettingsActivityTestRule(...)

  // UI tests here.
}

Java

@HiltAndroidTest
public final class SettingsActivityTest {

  @Rule(order = 0)
  public HiltAndroidRule hiltRule = new HiltAndroidRule(this);

  @Rule(order = 1)
  public SettingsActivityTestRule settingsActivityTestRule = new SettingsActivityTestRule(...);

  // UI tests here.
}

LaunchFragmentInContainer içi

androidx.fragment:fragment-testing kitaplığındaki launchFragmentInContainer, @AndroidEntryPoint ek açıklaması olmayan bir etkinliğe bağlı olduğu için Hilt ile kullanılamaz.

Bunun yerine architecture-samples GitHub deposundaki launchFragmentInHiltContainer kodunu kullanın.

Singleton bileşeni kullanılabilir hale gelmeden önce bir giriş noktası kullanın

@EarlyEntryPoint ek açıklaması, tekli bileşen bir Tepe testinde kullanılabilir hale gelmeden önce bir Hilt giriş noktası oluşturulması gerektiğinde bir çıkış penceresi sağlar.

@EarlyEntryPoint hakkında daha fazla bilgiye Hilt dokümanlarından ulaşabilirsiniz.